达叔的朋友圈们程序员程序员

第37节:多线程安全问题

2018-09-03  本文已影响58人  魔王哪吒
标题图

定义用户去银行存钱,每次存100,存3次

class Bank {
 // 总数
 private int sum;
// 定义方法
 public void add(int num){
  // 传入参数
  sum = sum + sum;
 // 加后的值
  System.out.println("sum"+sum);
 }
}

class Demo implements Runnable{
 // 定义银行类对象,创建实例对象
 private Bank  b = new Bank();
// 线程run()
 public void run(){
  for(int x=0; x<3; x++){
   // 将参数放入对象方法中
   b.add(100)
  }
 }
}

// 测试类
class Test{
 public static void main(String[] args){h
  // 创建对象
  Demo d=new Demo();
 // 创建线程对象
  Thread t1 = new Thread(d);
  Thread t2 = new Thread(d);
 // 线程开启
  t1.start();
  t2.start();
}
}

如果出现这个代码,出现了多线程安全问题。共性数据即共享对象中的数据。

class Bank {
 // 总数
 private int sum;
// 创建对象
 private Object obj = new Object();
// 定义方法
 public void add(int num){
  synchronized(obj){
  // 传入参数
  sum = sum + sum;
 // 加后的值
  System.out.println("sum"+sum);
 }
 }
}

安全问题,加了同步可以解决数据安全。

class Tickets implements Runnable{
 private int tickets = 100;
 private Object obj = new Object();
 public void run(){
  whilt(true){
   synchronized(obj){
    if(tickets>0){
     try{
      Thread.sleep(1000);
     }catch(Exception e){
      System.out.println(Thread.currentThread().getName()+tickets);
     }
    }
   }
  }
 }
}

饿汉式

class Single{
 private static final Single s = new Single();
 private Single(){)
 public static Single getInstance(){
  return s;
 }
}

懒汉式

class Single{
 private static Single s = null;
 private Single(){}
 public static Single getInstance(){
  if(s==null){
   s = new Single();
  }
 return s;
 }
}

多线程

在同一时间,做多件事情.

创建线程的方法
继承类Thread并重写run(),run()称为线程体;用这种方法定义的类不能再继承其他类。

class FirstThread extends Thread{
public void run(){
 for(int i=0;i<100;i++){
  System.out.println("FirstThread"+i);
 }
}
}

class Test{
public static void main(Sting args[]){
 FirstThread ft = new FirstThread();
 ft.start();
 
 for(int i = 0; i<100;i++){
  System.out.println("main"+i):
 }
}
}

接口Runnable的类作为线程的目标对象

class Test implements Runnable{
public void run(){
 for(int i = 0;i<100;i++){
  System.out.println("Runnable"+i);
 }
}
}

class Test{
public static void main(String args[]){
 Test test = new Test();
 Thread t = new Thread(test);
 System.out.println(t.getPriority());
 t.start();
}
}

唤醒线程

线程类


image.png

主方法类


image.png

线程同步与等待

image.png

线程的同步

关键字synchronized

多线程就是调用这个synchronized的方法的,
当线程用了这个方法,那么其他线程想使用这个方法时就得等,直到线程使用完该调用的方法。

同步中的等待

wait()方法:暂时让出cpu;
notifyAll()方法:等待结束。

线程是程序中的执行线程,在Java虚拟机中允许应用程序并发地运行多个执行线程,每个线程独有它自己的一个优先级,高的优先级的执行线程优先于低优先级的线程,每个线程都可以有或者不可以标记的一个守护程序。当一个线程中的运行代码创建一个Thread对象的时候,该线程的初始化优先级就被设定,只有创建线程是守护线程的时候,这个线程才是守护程序。

在Java中的虚拟机启动,通常会有单个非守护线程,一般在代码中有个线程为主线程,main方法。

第36节:Java当中的线程
第35节:Java面向对象中的多线程

这两篇文章讲了什么是进程,什么是线程等一些概念。

进程要执行需要依赖线程,线程是进程中最小的执行单位,一个进程中至少要有一个线程,在线程中串行是单条线程来执行多个任务来说的,任务A到任务B到任务C,只有任务A完成了后才开始到任务B,一条线完成。并行为开启多个线程同时进行任务,同一时刻发生任务A,任务B,任务C。

什么是线程安全

线程出现问题是在多线程的情况之下产生的。出现线程安全问题,如何去解决这个问题呢?用synchronized关键字,用来控制线程同步的,可以让线程在多线程的情况下,不被多个线程同时执行,保证我们数据的安全性。

public synchronized void add(int i){
 ...
}

Lock的引入让锁有了可操作性,它是在Java1.6被引入进来的,Lock可以去手动获取锁和释放锁。

// ReentrantLock是Lock的子类
private Lock lock = new ReentrantLock(); 

private void methodThread(Thread thread){
       // 获取锁对象
       lock.lock(); 
       try {
           System.out.println(thread.getName() + "获得了锁");
       }catch(Exception e){
           e.printStackTrace();
       } finally {
           System.out.println(thread.getName() + "释放了锁");
           // 释放锁对象
           lock.unlock(); 
       }
}

往后余生,努力学习
简书作者:达叔小生
90后帅气小伙,爱编程,爱运营,爱折腾。
简书博客: https://www.jianshu.com/u/c785ece603d1

结语

上一篇下一篇

猜你喜欢

热点阅读