多线程创建方式及线程安全问题

Posted 终难遇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程创建方式及线程安全问题相关的知识,希望对你有一定的参考价值。

1.创建线程方式

一:  创建线程方式一继承Thread

public clsss MyThread extends Thread{

    //重写run方法,设置线程任务

    Run(){

}

}

main(){

    new MyThread().start();

}

获取线程名称:

Thread.currentThread()获取当前线程对象

Thread.currentThread().getName();获取当前线程对象的名称

二:创建线程方式实现Runnable接口

 

创建线程的步骤。

 

1、定义类实现Runnable接口。

 

2、覆盖接口中的run方法。。

 

3、创建Thread类的对象

 

4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。

 

5、调用Thread类的start方法开启线程。

 

l  代码演示:

 

public class Demo02 {

 

    public static void main(String[] args) {

 

        //创建线程执行目标类对象

 

        Runnable runn = new MyRunnable();

 

        //Runnable接口的子类对象作为参数传递给Thread类的构造函数

 

        Thread thread = new Thread(runn);

 

        Thread thread2 = new Thread(runn);

 

        //开启线程

 

        thread.start();

 

        thread2.start();

 

        for (int i = 0; i < 10; i++) {

 

           System.out.println("main线程:正在执行!"+i);

 

        }

 

    }

三:两种方法的使用比较

第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。

第一种方式继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,又有线程任务。

实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

 

 

2     线程安全

 

如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

 

线程不安全:

 

1.     单线程没有线程安全问题

 

2.     多线程没有使用相同的内容,也会不出现安全问题

 

3.     多线线程使用了同一个资源,可能会出现线程安全问题

 

一:使用同步代码块解决线程安全问题

synchronized(锁对象){

      可能出现安全问题的代码

      (访问了共享数据的代码)

}

同步代码块: 在代码块声明上 加上synchronized

synchronized (锁对象) {

    可能会产生线程安全问题的代码

}

同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。

 

使用同步代码块,对电影院卖票案例中Ticket类进行如下代码修改:

publicclass Ticket implements Runnable {

    //100

    intticket = 100;

    //定义锁对象

    Object lock = new Object();

    @Override

    publicvoid run() {

        //模拟卖票

        while(true){

           //同步代码块

            synchronized (lock){

               if (ticket > 0) {

                   //模拟电影选坐的操作

                   try {

                       Thread.sleep(10);

                   } catch (InterruptedException e) {

                       e.printStackTrace();

                   }

                   System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);

               }

            }

        }

    }

}

注意:保证锁对象要唯一

二:使用同步方法解决线程安全问题

1.把访问共享数据的代码,提取出来放在一个方法中

 2.在方法上增加一个同步关键字

 

 修饰符 synchronized 返回值类型 方法名(参数列表){

    出现了安全问题的代码

    (使用了共享数据的代码)

 }

l  同步方法:在方法声明上加上synchronized

public synchronized void method(){

   可能会产生线程安全问题的代码

}

        同步方法中的锁对象是 this

       

使用同步方法,对电影院卖票案例中Ticket类进行如下代码修改:

publicclass Ticket implements Runnable {

    //100

    intticket = 100;

    //定义锁对象

    Object lock = new Object();

    @Override

    publicvoid run() {

        //模拟卖票

        while(true){

           //同步方法

            method();

        }

    }

 

//同步方法,锁对象this

    publicsynchronizedvoid method(){

        if (ticket > 0) {

           //模拟选坐的操作

           try {

               Thread.sleep(10);

           } catch (InterruptedException e) {

               e.printStackTrace();

           }

           System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);

        }

    }

}

 

l  静态同步方法: 在方法声明上加上static synchronized

public static synchronized void method(){

可能会产生线程安全问题的代码

}

静态同步方法中的锁对象是 类名.class

Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能。

我们使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Ticket类进行如下代码修改:

publicclass Ticket implements Runnable {

    //100

    intticket = 100;

   

    //创建Lock锁对象

    Lock ck = new ReentrantLock();

   

    @Override

    publicvoid run() {

        //模拟卖票

        while(true){

           //synchronized (lock){

           ck.lock();

               if (ticket > 0) {

                   //模拟选坐的操作

                   try {

                       Thread.sleep(10);

                   } catch (InterruptedException e) {

                       e.printStackTrace();

                   }

                   System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);

               }

           ck.unlock();

           //}

        }

    }

}

以上是关于多线程创建方式及线程安全问题的主要内容,如果未能解决你的问题,请参考以下文章

如何创建线程?如何保证线程安全?

线程的创建方式安全状态

多线程

java多线程创建方式以及线程安全

面向加薪重学Java多线程(三种创建方式,线程安全,生产者消费者)

锁和多线程:线程创建3种方式