Java多线程及线程安全详解

为什么要使用多线程:

单线程只能干一件事,而多线程可以同时干好多事(将任务放到线程里执行  效率高),而所谓同时干并不是真正意义上的同时,只是(这里就叫CPU)cpu在每个线程中随机切换来执行 线程中要干的活。

多线程编写:

1)第一种:(线程类)

class Stu1 extends Thread{

  //重写 run方法 

}

调用:Stu1 su = new Stu1();

su.start()//内部会自动调用run方法    把run方法放到线程上调用

2)第二种:普通任务类(由于第一种类只能是单继承 就没法实现继承其他父类并且继承线程类 所以第一种方法扩展性比较差)

直接创建线程对象,线程内干的事,放到一个自定义对象里面实现(用到修饰设计模式)

底层代码

class Thread{

private Runnable r

public void Thread(Runnable r){ //利用有参构造将自定义对象传进来

this.r = r;

}

public void start(){

  r.run();

}

}

class Stu implements Runnable{}  通过实现接口  线程类底层start调用的run方法 实际就是我们自定义类中的run方法

Thread th = new  Thread(new Stu())  //直接创建线程对象

th.start();

我们用第二种方法创建多线程如下:

public static void main(String[] args) {
//      不同线程干同一件事
        SaleWindow sw = new SaleWindow();
        Thread t1 = new Thread(sw);
        Thread t2 = new Thread(sw);
        t1.setName("窗口A");
        t2.setName("窗口B");
        t1.start();
        t2.start();
    }

public class SaleWindow implements Runnable {
    private int ticketCount = 10;
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
//      多个窗口卖票
        for(int i = 0;i<10;i++){
            if(ticketCount>0){
                //字符串拼接信息  变量+""  就可以拼接成字符串
                System.out.println(Thread.currentThread().getName()+"卖出"+ticketCount+"张票");
                ticketCount--;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
//                  e.printStackTrace();
                }
            }
        }
    }
   
}

最后结果图:

Java多线程及线程安全详解

从运行结果来看:同一张票卖给了二个人  这是在现实生活中不允许的 这样就会产生线程安全问题。

而产生线程安全问题的有三个要素必须同时满足才会产生线程安全:

1、必须有共享资源
2、必须是多线程环境
3、每个线程都适用了共享资源

而上面的例子:票是共享资源、又是多线程环境、线程执行任务的时候又使用了共享资源 所以会产生线程安全

怎么解决线程安全?

解决线程安全其核心:就是将某一个线程中的任务给锁(同步锁)起来,这个时候JVM就不得不等到本任务里的代码执行完以后在去执行另外一个线程里的任务。

二种方法:

1、同步代码块:

public class SaleWindow implements Runnable {
    private int ticketCount = 10;
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
        // 多个窗口卖票
        for (int i = 0; i < 10; i++) {//可以随意设置锁
            synchronized (this) {
                if (ticketCount > 0) {
                    // 字符串拼接信息 变量+"" 就可以拼接成字符串
                    System.out.println(Thread.currentThread().getName() + "卖出"
                            + ticketCount + "张票");
                    ticketCount--;
                    try {
                        Thread.sleep(500);//每隔500毫秒 线程休眠 随后自己自动会唤醒(目的是为了调节线程速度)
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        // e.printStackTrace();
                    }
                }
            }
        }
    }
 
}

2、同步方法:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b145f80c36bfc6282167b1f511ace1ec.html