Java---13---多线程:解决多线程的安全问题---synchronized 同步代码块

还是之前卖票的例子:

class Test implements Runnable
{
    private int num = 50;
    Object obj = new Object();
    public void run ()
    {
        while (true)
        {
            if (num >= 0)
            {
                try
                {
                    Thread.sleep(20);
                }
                catch (Exception e)
                {
                    // TODO: handle exception
                    System.out.println(e.toString());
                }
                System.out.println(Thread.currentThread().getName()+">>"+num--);
            }
        }
    }
}

public class RUNNABLE
{
    public static void main (String[] args)
    {
        Test t = new Test();
        Thread a = new Thread(t);
        Thread b = new Thread(t);
        Thread c = new Thread(t);
        Thread d = new Thread(t);

        a.start();
        b.start();
        c.start();
        d.start();
    }
}

在打印结果发现出现了 -1,-2,这与实际是不相符的,也许你会有疑问,不是num >= 0的时候才输出结果的吗,为什么会出现负数呢?

这就是多线程的安全问题。

 

解释一下:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。

假如说输出结果是这样的:

Thread-2...0

Thread-0...-1

Thread-3...-2

可能造成这样的结果的原因是:

当num=0的时候0线程来了,睡了,3线程来了,也睡了,这个时候2线程sleep的时间到了,醒过来了,这时2线程执行程序,输出结果为0,之后0线程和3线程醒了过来,然后它们接着执行程序,不需要再判断num是否符合条件,因为在它们睡之前就已经判断过了,所以再输出结果的时候,num的值已经变为负数了。这就是会输出负数的原因。

 

解决办法:

对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可参与。

对于多线程的解决方式:同步代码块

格式:

synchronized (对象)

{

//需要被同步的语句

}

解决方案:

class Test implements Runnable
{
    private int num = 50;
    Object obj = new Object();
    public void run ()
    {
        while (true)
        {
            synchronized (obj)
            {
                if (num >= 0)
                {
                    try
                    {
                        Thread.sleep(20);
                    }
                    catch (Exception e)
                    {
                        // TODO: handle exception
                        System.out.println(e.toString());
                    }
                    System.out.println(Thread.currentThread().getName()+">>"+num--);
                }
            }
        }
    }
}

public class RUNNABLE
{
    public static void main (String[] args)
    {
        Test t = new Test();
        Thread a = new Thread(t);
        Thread b = new Thread(t);
        Thread c = new Thread(t);
        Thread d = new Thread(t);

        a.start();
        b.start();
        c.start();
        d.start();
    }
}

哪些代码需要被同步就要看哪些语句在操作共享数据。

 

同步代码块的工作原理:

 synchronized (obj)

{

    //被同步的代码

}

 

在需要被同步的代码外加了synchronized(obj) 就相当于将需要被同步的代码关进了一个房间,obj就相当于这个房间的锁,一开始默认这个锁是打开的,当某一个线程需要执行被同步的代码的时候,需要先判断能不能进入到这个房间,也就是这个锁是不是打开的。如果锁是打开的,那么这个线程就会进入到房间里,从而执行被同步的代码,顺便把锁锁上了,锁上之后,别的线程如果也要运行被同步的代码的时候,也需要先判断能不能进去,但这个时候的锁是锁上的,也就是说,别的线程进不去。也就是说,只要有线程在执行被同步的代码的时候,别的线程是无法再执行的。当线程执行完了被同步的代码的时候,出去这个房间的时候,就将锁打开了,这个时候,其他的线程才有机会进入到这个房间执行代码。

 

同步的前提:

1.必须是两个及两个以上的线程

就一个线程就不需要锁了,所有的代码都是它来执行

2.必须是多个线程使用同一个锁

意思就是多个线程都进一个房间,如果每个线程进入各自对应的房间,锁与不锁又有什么区别

保证房间内只有一个线程

 

 

好处:解决安全性问题

弊端:线程在执行代码的时候需要判断锁,消耗了一定的资源。

时间: 2024-10-14 18:53:10

Java---13---多线程:解决多线程的安全问题---synchronized 同步代码块的相关文章

java中多线程模拟(多生产,多消费,Lock实现同步锁,替代synchronized同步代码块)

import java.util.concurrent.locks.*; class DuckMsg{ int size;//烤鸭的大小 String id;//烤鸭的厂家和标号 DuckMsg(){ } DuckMsg(int size, String id){ this.size=size; this.id=id; } public String toString(){ return id + " 大小为:" + size; } } class Duck{ private int

java:synchronized 同步代码块

synchronized:利用上锁实现数据同步,避免多线程操作的情况下,数据出现异常. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行. 另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块. 在代码块前加上 synchronized关键字,则此代码块就成为同步代码块, 格式: synchronized(同步对象){ 需要同步的代码: } class MyThread implements Runnab

阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第3节 线程同步机制_4_解决线程安全问题_同步代码块

同步代码块 解决了线程安全的问题. 原文地址:https://www.cnblogs.com/wangjunwei/p/11260470.html

Java并发学习之十四——使用Lock同步代码块

本文是学习网络上的文章时的总结,感谢大家无私的分享. Java提供另外的机制用来同步代码块.它比synchronized关键字更加强大.灵活.Lock 接口比synchronized关键字提供更多额外的功能.在使用Lock时需要注意的是要释放Lock锁. package chapter2; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * 打印队列 */ pu

synchronized同步代码块锁释放

今天发现自己写的线上程序出现数据库不能同步的问题,查看日志已经停止记录,随后使用jstack查看线程的运行状况,发现有个同步线程锁住了. 以下是jstack -l 637  问题线程的内容. "schedulerJob-t-291" #314 daemon prio=5 os_prio=0 tid=0x00007f7d64844800 nid=0x3d5 runnable [0x00007f7d3a107000] java.lang.Thread.State: RUNNABLE at

JAVA高并发程序设计学习:Synchronized同步代码块具体使用方法

多线程同时对资源进行访问时,同步机制使得同一时间内只能有一个线程对资源进行操作. 同步机制可以用Synchronized实现. 当Synchronized修饰一个方法的时候,该方法称为同步方法. 当Synchronized方法执行完成或者异常时会释放锁. 会有同学对synchronized修饰方法,静态方法,对象时具体对哪些东西加锁不是很明白,这里会进行详细的讲解. synchronized修饰方法时,会对类实例进行加锁,该实例的所有synchronized方法必须等当前锁释放后才能访问. sy

synchronized 同步代码块,售票问题

package cn.ljs.FristSync; public class SalerDemo extends Thread { static int tickets = 1000; String name; static Object lock = new Object(); public SalerDemo(String name) { this.name = name; } public void run(){ while(true){ synchronized (lock) { if

java多线程(三)——锁机制synchronized(同步语句块)

用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法之行一个长时间的任务,那么B线程必须等待比较长的时间,在这样的情况下可以使用synchronized同步语句快来解决. 一.用同步代码块解决同步方法的弊端 Task类 1 package com.weishiyao.learn.day4.testSynchorized.ep2; 2 3 public class Task { 4 5 private String getData1; 6 private Stri

synchronized静态代码块,以及其中的wait,notify和notifyAll

接触Java多线程这么久了,synchronized静态代码块以及其中的wait和notify方法一直没搞懂,网上关于此,不是旁敲侧击,就是晦涩难懂(我理解能力有限),实在无语了.今天把Java的源码导入到了eclipse,从源码中看到了我想要的答案. 即本文专注于讲解透彻地讲解synchronized代码块,wait以及notify的使用方法,绝对一针见血,绝不旁敲侧击,没意思. 注:本文不会讲什么是Java同步机制,以及为何要同步 我们开始吧. 一.抛出问题 1.notify和wait到底是