java多线程——线程的同步

chen_hao      2022-04-17     362

关键词:

实现Runnable接口

public class TestThread2 {
    public static void main(String [] args){
        Window window=new Window();
        Thread thread1=new Thread(window,"窗口一");
        Thread thread2=new Thread(window,"窗口二");
        Thread thread3=new Thread(window,"窗口三");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class Window implements  Runnable{
    int ticket=50;
    @Override
    public void run(){
        while (true){
            if(ticket > 0){
                try {
                    Thread.currentThread().sleep(100);//模拟卖票需要一定的时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--);
            }else {
                break;
            }
        }
    }
}

运行结果:

窗口二售票,票号为:13
窗口三售票,票号为:12
窗口一售票,票号为:11
窗口二售票,票号为:10
窗口一售票,票号为:10
窗口三售票,票号为:10
窗口三售票,票号为:9
窗口一售票,票号为:8
窗口二售票,票号为:7
窗口三售票,票号为:6
窗口一售票,票号为:5
窗口二售票,票号为:4
窗口三售票,票号为:3
窗口一售票,票号为:2
窗口二售票,票号为:1
窗口三售票,票号为:0
窗口一售票,票号为:-1

 

结果分析:这里出现了票数为0和负数还有重票的情况,这在现实生活中肯定是不存在的,那么为什么会出现这样的情况呢?

  当票号为10时:A线程、B线程、C线程同时进入到if(ticket > 0)的代码块中,A线程已经执行了打印输出语句,但是还没有做ticket--操作;
  这时B线程就开始执行了打印操作,那么就会出现两个线程打印票数一样,即卖的是同一张票
  当票号为1时:A线程、B线程,C线程同时进入到if(ticket > 0)的代码块中,A线程执行了打印语句,并且已经做完了ticket--操作,则此时ticket=0;
  B线程再打印时就出现了0的情况,同理C线程打印就会出现-1的情况。

解决办法:即我们不能同时让超过两个以上的线程进入到 if(ticket > 0)的代码块中,不然就会出现上述的错误。必须让一个线程操作共享数据完毕以后,其他线程才有机会参与共享数据的操作。我们可以通过以下两个办法来解决:

  1、使用 同步代码块

  2、使用 同步方法

使用 同步代码块

synchronized(同步监视器){
      //需要被同步的代码块(即为操作共享数据的代码)
}

  同步监视器:由任意一个类的对象来充当,哪个线程获取此监视器,谁就执行大括号里被同步的代码。俗称:锁

  要求:1、所有的线程必须公用同一把锁!不能相对于线程是变化的对象;

        2、并且只需锁住操作共享数据的代码,锁多了或少了都不行;

 

实例:

1、实现的方式

public class TestWindow {
    public static void main(String [] args){
        Window1 window=new Window1();
        Thread thread1=new Thread(window,"窗口一");
        Thread thread2=new Thread(window,"窗口二");
        Thread thread3=new Thread(window,"窗口三");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class Window1 implements  Runnable{
    int ticket=100;//共享数据
    @Override
    public void  run(){
        while (true){
            synchronized (this){//this表示当前对象,此时表示创建的 window
                if(ticket > 0){
                    try {
                        //模拟卖票需要一定的时间
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--);
                }
            }
        }
    }
}

注意:在实现的方式中,考虑同步的话,可以使用this充当锁,但在继承的方式中,会创建多个对象,慎用this

2、继承的方式

public class TestWindow1 {
    public static void main(String [] args){
        Window2 window1=new Window2();
        Window2 window2=new Window2();
        window1.start();
        window2.start();
    }
}


class Window2 extends Thread{
    static int ticket=100;//共享数据;注意声明为 static,表示几个窗口共享
    static Object object=new Object();//用static 可以表示唯一
    @Override
    public void  run(){
        while (true){
            //synchronized (this){//this表示当前对象,此时表示创建的 window1和window2
            synchronized (object){//锁必须是唯一,不能每个线程都使用自己的一把锁
                if(ticket > 0){
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--);
                }
            }
        }
    }
}

注意:1、继承的方式会创建多个实例,所以共享资源需要用static来修饰,表示共享

      2、继承的方式会创建多个实例,所以 this 表示不同的实例对象,这里表示widow1和window2,所以不能使用this当锁,此时可以定义一个 static 修饰的对象当锁

 

使用 同步方法

语法:即用  synchronized  关键字修饰方法

将操作共享数据的方法声明为synchronized。即此方法为同步方法,能够保证当其中一个线程执行此方法时,其他线程再外等待直至此线程执行完此方法。
注意:同步方法的锁:this

实例:

1、实现的方式

public class TestWindow2 {
    public static void main(String [] args){
        Window3 window=new Window3();
        Thread thread1=new Thread(window,"窗口一");
        Thread thread2=new Thread(window,"窗口二");
        Thread thread3=new Thread(window,"窗口三");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class Window3 implements  Runnable{
    int ticket=100;//共享数据
    @Override
    public void  run(){
        while (true){
            show();
        }
    }

    public synchronized void show(){//this充当锁,此时表示创建的 window;
        // 如果用继承的方式,使用同步方法,这里表示创建的 window1和window2,继承的方式不要使用同步方法
        if(ticket > 0){
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--);
        }
    }
}

 

注意:1、synchronized 的锁为this,这里表示创建的对象实例window;

     2、继承的时候t this 表示创建的window1和window2,继承的方式不要使用同步方法。

java多线程

11.1)多线程概念11.2)创建多线程的2种方法11.3)多线程的生命周期11.4)同步(掌握)为什么需要同步?因为线程安全问题,举例—银行取钱问题,多线程对同一个银行账户进行取钱任务,账户会出现负值的资产,不符合现实生... 查看详情

java多线程有几种实现方法?线程之间如何同步

java中多线程的实现方法有两种:1.直接继承thread类;2.实现runnable接口;同步的实现方法有五种:1.同步方法;2.同步代码块;3.使用特殊域变量(volatile)实现线程同步;4.使用重入锁实现线程同步;5.使用局部变量实现线程同步。其... 查看详情

java_多线程实现同步

多线程之间实现同步理解线程安全synchronized用法死锁Java内存模型Vlolatile关键字ThreadLock 关键字 理解线程安全 什么是线程安全?当多个线程同时对共享的同一个全局变量或静态变量做写的操作时,可能会发生数据冲突... 查看详情

java中多线程的线程同步死锁问题

/**定义一个多线程*/packagecom.thread;publicclassTicketThread2implementsRunnable{//定义1000张票 publicstaticintticket=100; Objectobj=newObject(); // publicbooleanflag=false; // publicbooleanexit=false; @Overr 查看详情

java多线程之线程同步

一、多线程出现的安全问题:1、问题的原因:多个线程执行的不确定性引起执行结果的不稳定。当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致... 查看详情

java中多线程安全性和同步的常用方法

1、多线程安全性问题,即多线程在什么场景下会出现异常?多个线程同时调用一个共享的变量(对象),比如当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。 2、在Java中,我们通过同步机... 查看详情

java多线程(线程安全,线程同步)

一.线程安全如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。通过电影院卖票,演示线程的安全... 查看详情

java多线程-线程同步简述

为什么要线程同步由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问机制上的冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制(synchronized),当一个线程对象获得对象的排他锁,独... 查看详情

java多线程基本概述——同步

非线程安全其实是在多个线程对同一个对象实例的变量进行并发访问的时候发生,产生的后果就是脏读,也就是取到的数据是修改过的。而线程安全就是获得的实例变量的值是经过同步处理的,从而不会出现脏读现象。1.1.1、实... 查看详情

java程序设计多线程基础

多线程基础文章目录多线程基础一、线程的概念(1)进程(2)线程二、线程的创建(1)Thread1.Thread类2.Thread类的子类来创建线程3.在新线程中完成计算某个整数的阶乘4.构造函数5.常用方法(2)Runnable1.Runnable接口2.Runnable接口的使用三、线程... 查看详情

java多线程-同步块

Java同步块(synchronizedblock)用来标记方法或者代码块是同步的。Java同步块用来避免竞争。本文介绍以下内容:Java同步关键字(synchronzied)实例方法同步静态方法同步实例方法中同步块静态方法中同步块Java同步示例Java同步关键... 查看详情

java多线程

使用synchronized锁实现线程同步为什么要用线程同步我们先来看下这段代码的运行结果:Java学习交流群:495273252在多线程上篇博客已经介绍过了,JVM采用的是抢占式调度模型,当一个线程sleep的时候,其它线程会抢占CPU资源。如果... 查看详情

java多线程synchronized同步

非线程安全问题“非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程问题”。也即是说,方法中的变量永远是线程安全的。如果多个线程共同访问1个对象中的实例变量... 查看详情

java多线程之代码同步

 多线程共享数据(多个线程共同访问相同的数据),需要进行数据同步,保证同一数据、同一时刻只能被一个线程访问。使用同步是为了防止多个线程同一时刻对同一数据进行读写,如果对同一数据数据都只进行读操作、不... 查看详情

java线程的同步

问题的引出在java语言中,我们常常会用到多线程相关的操作,但是多线程操作中可能会出现一些问题。现在给定一个抢票的多线程代码classMyThreadimplementsRunnable{inta=10;//票数@Overridepublicvoidrun(){while(true){if(a>0){try{Thread.sleep(1000);}ca... 查看详情

java同步—线程和进程

进程和线程1.线程和进程的定义进程定义:一个程序在一个数据集上的一次动态执行过程。简单来说:如果把进程比喻成桌子,线程比喻成人,程序比喻成吃饭。1.单进程单线程:一个人在一个桌子上吃饭2.单进程多线程:一堆人... 查看详情

java并发编程之多线程同步

线程安全就是防止某个对象或者值在多个线程中被修改而导致的数据不一致问题,因此我们就需要通过同步机制保证在同一时刻只有一个线程能够访问到该对象或数据,修改数据完毕之后,再将最新数据同步到主存中,使得其他... 查看详情

java多线程--“锁”总览

...原理是,对于每一个对象,有且仅有一个同步锁;不同的线程能共同访问该同步锁。但是,在同一个时间点,该同步锁能且只能被一个线程获取到。这 查看详情