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


    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();

               //}

            }

        }

    }

  • 相关阅读:
    局部组件
    flex布局
    Websocket
    关于Javascript夜里再来分析下
    go build、go mod等命令
    websocket
    FileSystemWatcher使用
    DataGridView双缓冲
    C#读INI文件
    c 通过 COM接口调用 Excel.Application 问题终于解决
  • 原文地址:https://www.cnblogs.com/outsidersblogs/p/7020442.html
Copyright © 2020-2023  润新知