精华内容
下载资源
问答
  • 关于线程同步

    千次阅读 2008-04-13 00:14:00
    一直很习惯在窗口对象的析构函数中等待子线程终止, 现在才发现是一个巨大的错误,子线程给界面线程发消息,要依赖窗口的存在,当对象析构时,窗口早就不复存在,所以结束子线程的最佳位置是窗口处理WM_DESTROY消息...

    一直很习惯在窗口对象的析构函数中等待子线程终止, 现在才发现是一个巨大的错误,子线程给界面线程发消息,要依赖窗口的存在,当对象析构时,窗口早就不复存在,所以结束子线程的最佳位置是窗口处理WM_DESTROY消息的时候。

     

    流水一篇,Over。

    展开全文
  • 为什么去掉push和pop的synchronized修饰关键词时,会报如下错误 异常: Exception in thread "Thread-0" java.lang.IllegalMonitorStateException at java.lang.Object.notify(Native Method) at 线程.TestTeread_...
  • 当多线程对共享属性进行操作时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程就参与进来进行执行,导致共享属性错误。解决办法: 对于多操作共享属性的语句,只能让一个线程执行完。在执行过程中,另...

    线程安全是多线程中一个很重要的知识点,渣渣我结合体会写一些,以便加深印象。

    ⑴问题原因:
    当多线程对共享属性进行操作时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程就参与进来进行执行,导致共享属性错误。

    解决办法:
    对于多操作共享属性的语句,只能让一个线程执行完。在执行过程中,另一个属性不可以参与执行
    ⑵JAVA对于安全问题提供了专业的解决方法:
    就是同步代码块
    关键字:synchronized(对象)

    需要被同步的代码
    PS。即对共享数据进行操作的代码

    ⑶括号内的对象有什么用?
    对象中有锁旗标,即“锁”,或者叫“监视器”。当一个线程进入后持有锁,锁会关闭,
    当进程对共享属性的一次操作完成后,锁会解开,另一个线程可以进入。
    对象就是充当“锁”的作用。

    ⑷使用同步代码块的前提:
    1.有多个线程
    2.共用一个锁

    ⑸用同步块的利弊
    好处:解决了多线程的安全问题
    弊端:因为每次对共享属性进行操作,都需要对锁进行判断。消耗的运行资源,会使程序运行变慢

    ⑹如何找哪些代码该同步
    1.明确哪些代码是多线程代码
    2.明确共享数据
    3.明确多线程运行代码中哪些语句是操作共享数据的

    ex:(一个关于两个账户向银行存钱的小例子)

    class Bank
    {
    private double money = 0;
    Object obj = new Object();
    
    public void add(double x)
    {
        synchronized(obj)
        {
        money+=x;
        System.out.println("now your money is "+money);
        }
    }
    }
    
    class User implements Runnable
    {
    private Bank f = new Bank();
    public void run()
    {
        for(int i =0;i<3;i++)
            f.add(100);
    }
    }
    public class Demo1
    {
    public static void main(String[] args) {
        User f = new User();
        Thread t1 = new Thread(f);
        Thread t2 = new Thread(f);
        t1.start();
        t2.start();
    }
    }
    

    ⑺同步函数
    方式:在函数的修饰符中加synchronized
    PS.要加在返还值类型修饰符之前

    1.同步函数在一般情况下使用的锁是this
    2.同步函数在被静态修饰时,使用的 锁 是该方法所在类的字节码文件的对象。即 类名.class

    因为知识点有点杂,所以渣渣只能总结一下。如果有错,还请指正,渣渣我感激不尽。

    以上。

    展开全文
  • 线程同步

    2020-05-25 15:58:30
    这就是我在前面谈到关于线程安全的时候所说的火车票的例子。 这次我们来谈一个银行的例子: 步骤如下: 1、用户输入账户,密码,系统判断用户的账户,密码是否匹配。 2、用户输入取款余额。 3、系统判断账户余额是否...

    多线程编程是有趣的事情,它很容易出现错误的情况。这就是我在前面谈到关于线程安全的时候所说的火车票的例子。

    作为线程同步的知识,还是直接上代码来的比较清晰,首先为什么要有线程同步呢?
    首先自己书写一个线程类MyThread1

    package mythread;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    
    /** 
    
    * @author Hercules
    
    * @version 创建时间:2020年5月25日 下午2:40:01 
    
    * 类说明 
    
    */
    public class MyThread1 implements Runnable{
    	
    	private List<String> lists = new ArrayList<String>();
    	
    	private static int count = 0;
    	
    	public void getList() {
    		System.out.println(count);
    		System.out.println(lists);
    	}
    	
    	public void update() {
    		count++;
    		lists.add(count+"a");
    	}
    
    	@Override
    	public void run() {
    		
    		for(int i = 0;i<100;i++) {
    			update();
    		}
    		
    	}
    
    	
    	
    }
    

    前面我的博客也提到了ArrayList它是线程不安全的。接下来再来写一个测试类:

    package mythread;
    /** 
    
    * @author Hercules
    
    * @version 创建时间:2020年5月25日 下午2:45:24 
    
    * 类说明 
    
    */
    public class Test {
    
    	public static void main(String[] args) {
    		MyThread1 thread1 = new MyThread1();
    		Thread thread = new Thread(thread1);
    		thread.start();
    		Thread thread2 = new Thread(thread1);
    		thread2.start();
    		Thread thread3 = new Thread(thread1);
    		thread3.start();
    		Thread thread4 = new Thread(thread1);
    		thread4.start();
    		Thread thread5 = new Thread(thread1);
    		thread5.start();
    		Thread thread6 = new Thread(thread1);
    		thread6.start();
    		
    		thread1.getList();
    	}
    	
    }
    
    测试类中共有六个线程启动了,所以理论上来说私有成员变量lists中应该有600个数据了,因为有六个线程同时操作lists。但是实际的运行结果如下:
    

    在这里插入图片描述
    这里报了一个越界异常(这段程序的运行结果有不确定性,可能报越界异常,也可能报别的异常,当然也可能不报异常),但是请注意ArrayList的特性,ArrayList是自动扩容的,所以怎么可能越界呢?

    答案是比如开始lists只能放10个数据,当第11个数据被一个线程送过来的时候,刚好开始扩容,但是当扩容没结束的时候,另一个线程又把数据放了进去这就产生了数组越界异常,而且可以看到上面的数据没有1a,并且还有null数据,那么这就是线程不同步造成的。

    好,既然问题出现了就解决这个问题。第一种方法是将代码中的

    private List<String> lists = new ArrayList<String>();
    

    改成:private List<String> lists = new Vector<String>();
    Vector是线程安全的所以不会出现上述问题,但是用Vector也会有一个难以解决的问题,下面我改成Vector来运行一下:
    在这里插入图片描述
    可以看到有些数据重复了,有些数据没有,并不是因为Vector的锅,而是方法的问题,具体症结在于

    public void update() {
    		count++;
    		lists.add(count+"a");
    	}
    

    在这个方法中,可能count刚刚变化,本次线程还没来得及执行add方法。下一个线程就又过来执行count++了,所以两次add方法加进去的元素是一样的。

    还有第二种方法就是加同步锁了。代码如下:
    将update方法改成如下形式:

    public synchronized void update() {
    		count++;
    		lists.add(count+"a");
    }
    

    在这里插入图片描述
    可以看到现在所有的数据都顺序打印了出来。

    这个就是线程同步,我们刚才用的方法叫做同步方法

    public synchronized void update() {
    		count++;
    		lists.add(count+"a");
    }
    

    主要使用了synchronized 关键字。当给update方法加上了这个关键字,就相当于给这个方法上了一把同步锁,当第一个线程调用该方法的时候,会给方法加一个同步锁,其他线程如果调用这个方法就会阻塞(等待同步锁),当第一个线程执行完该方法,会释放同步锁,其他线程就会重新加入队列调用该方法和上厕所是一样的,比如厕所的坑位你把门锁上了,别人就进不来了,只有你完事儿了,别人才能进来办事。具体底层是什么,先不要问,这就涉及到了java虚拟机的东西,先把这一段话理解记住。

    不过其实还有别的解决办法,同步块

    @Override
    	public void run() {
    		
    		synchronized (lists) {
    			for (int i = 0; i < 100; i++) {
    					update();
    			}
    		}
    		
    	}
    

    把run方法改成上述代码,运行结果如下:
    在这里插入图片描述
    当线程执行时,会给lists添加同步锁,其他的线程就需要等待,直到第一个线程执行完代码块里面的内容,则释放同步锁,其他线程才会去加入队列继续执行线程

    展开全文
  • Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享...

    Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文)


    • 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享给大家,本人的水平有限,如果我的分析或者结论有错误希望大家一定要帮我指出来,我好能改正和提高

    一、对于线程同步和同步锁的理解(注:分享了三篇高质量的博客)


    以下我精心的挑选了几篇博文,分别是关于对线程同步的理解和如何选择线程锁以及了解线程锁的作用范围。

    <一>线程同步锁的选择

    1. 这里我推荐下陆先生的Java代码质量改进之:同步对象的选择这篇博文。

    2. 以上推荐的博文是以卖火车票为例,引出了非同步会导致的错误以及同步锁(监视器)应该如果选择,应该能够帮助大家理解同步锁。


    <二>线程同伴锁用法及同步锁的作用范围

    1. 这里我推荐下Java中synchronized同步锁用法及作用范围这篇博文。

    2. 以上的博文将静态锁(字节码文件锁)和非静态锁(this)进行了对比,以及将线程非同步和线程同步下进行了对比,对大家了解线程锁的用法和作用范围有很大的帮助。

     

    <三>对线程同步的理解

    1. 这里我推荐下java中线程同步的理解(非常通俗易懂)这篇博文。

    2. 以上推荐的博文以非常通俗易懂的观点解释了到时什么同步,将同步理解成了线程同步就是线程排队,而且举了一些日常生活中的例子来让大家理解到底什么是同伴。

     

    <四>同步的作用场景

    1. 并不是说同步在什么情况下都是好的,因为线程的同步会带来较低效率,因为线程同步就代表着线程要排队,即线程同步锁会带来的同步阻塞状态。

    2. 因为CPU是随意切换线程的,当我们想让当前线程执行之后CPU不随意切换到其他线程,或者我们想要让某个线程的代码能够在完全执行之前不会被抢夺执行权,不会导致从而无法连续执行,那么我们就需要线程的帮助。

     

    二、线程同步和线程通信的几个小细节


    以下是我在学习线程同步时,遇到的小问题和我的小感悟

     <一>线程sleep方法的基本用法和注意细节

        1.sleep方法的基本用法

    Thread.sleep(long millis),传入毫秒数(1秒 = 1000毫秒),在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。(~注:Java技术文档的意思就是该线程休眠指定的毫秒数,而且休眠状态暂时失去CPU执行权,而且线程醒来后,该线程不会释放锁。)

     1 /**
     2  * 
     3  * Thread.sleep的计时器用法
     4  *
     5  */
     6 public class ThreadSleepTest {
     7 
     8     public static void main(String[] args) {
     9         new Thread() {
    10             @Override
    11             public void run() {
    12                 int timeCount = 10;
    13                 while (timeCount >= 0) {
    14                     if (timeCount == 0) {
    15                         System.out.println("新年快乐!~");
    16                         break;
    17                     }
    18                     System.out.println("还剩" + timeCount-- + "秒");
    19                     try {
    20                         Thread.sleep(1000);
    21                     } catch (InterruptedException e) {
    22                         e.printStackTrace();
    23                     }
    24                 }
    25             }
    26         }.start();
    27     }
    28 
    29 }

     

        2.sleep方法使用的位置选择

    我在使用sleep方法时发现,当sleep的位置不一致所放的位置不同时,线程所运行的结果也是大不相同的,以下的代码是为了举例子,并不是说这个同步代码块就是应这样写(其实这段代码这么写是有很大的问题的,因为同步资源的选择不准确),至于同步资源的选择我在第二个大问题会讲到。

        • A 以下的代码是sleep方法出现在了售票的代码块之前,这时出现了负票。(可能时间上也会导致差异,但是这里先不考虑时间时间因素,时间因素等下讲。)
     1 package javase.week4;
     2 
     3 public class SellTrainTickets {
     4 
     5     public static void main(String[] args) {
     6         new MyThread("窗口1").start();
     7         new MyThread("窗口2").start();
     8         new MyThread("窗口3").start();
     9         new MyThread("窗口4").start();
    10     }
    11 
    12 }
    13 
    14 class MyThread extends Thread {
    15     
    16     static int tickets = 100;
    17 
    18     public MyThread(String name) {
    19         super(name);
    20     }
    21 
    22     @Override
    23     public void run() {
    24         while (tickets > 0) {//假设这已经减到了1  1>0 然后窗口1 窗口2 窗口3 窗口4 都进入循环
    25             try {
    26                 Thread.sleep(20);
    27                 
    28             } catch (InterruptedException e) {
    29                 e.printStackTrace();
    30             }
    31             synchronized (MyThread.class) {
    32                 System.out.println(getName() + "卖出了第" + tickets-- + "张票!");//然后0 -1 -2 -3,这时就出现了负票
    33             }
    34         }
    35     }
    36 }

     

        • B 以下的代码是sleep方法出现在了售票的代码块之后,这里没有出现负票了,在票数100的情况下,而且时间是20毫秒的情况下,该段代码正好保证了时间点上的合理性,但是相同情况下sleep方法出现在输出售票之前的代码就会出现错误,即使改变时间和票数其sleep方法出现的位置错误,还是会导致了在票数为负的情况。(其实如果票数更改或者时间的改变也可能导致sleep方法出现在售票代码块之后的情况下负票的出现)
     1 public class SellTrainTickets {
     2 
     3     public static void main(String[] args) {
     4         new MyThread("窗口1").start();
     5         new MyThread("窗口2").start();
     6         new MyThread("窗口3").start();
     7         new MyThread("窗口4").start();
     8     }
     9 
    10 }
    11 
    12 class MyThread extends Thread {
    13     
    14     static int tickets = 100;
    15 
    16     public MyThread(String name) {
    17         super(name);
    18     }
    19 
    20     @Override
    21     public void run() {
    22         while (tickets > 0) {//假设这已经减到了0  5>0 然后窗口1 窗口2 窗口3 窗口4 都进入循环
    23             synchronized (MyThread.class) {
    24                 System.out.println(getName() + "卖出了第" + tickets-- + "张票!");//然后 3 2 1 0
    25             }
    26             try {
    27                 Thread.sleep(20);//此时票数等于0,这时窗口1 窗口2 窗口3 窗口4 都处于休眠,然后如果这里的时间合理的话,再次判断的话,正好在等于0的时候,都没有线程再次进入循环,也就不会出现负票了
    28                 
    29             } catch (InterruptedException e) {
    30                 e.printStackTrace();
    31             }
    32         }
    33     }
    34 }

     

        • C 总结下其实sleep方法出现的位置可能会影响到线程的结果,但是其实一般情况下是不会这么样去使用的,这里只是为了演示下sleep方法在位置不同的情况下出现的不同的结果,目的是为了让大家注意编程的细节。

     

         3.sleep方法的传入参数的选择

    sleep方法的传入的毫秒数对于线程的运行结果是有较大的影响的,最直接简单的影响就是让运行延迟了,但是除了这个以外其实也让线程的运行结果发生了变化,顺便分享一篇一篇高质量的博文Sleep(0)的妙用

        • A  当传入的参数为100时,以下是代码演示和执行结果,几乎每一个窗口(线程)都可以抢夺到运行权,而且比较分散。
     1 public class TicketsThreadTest {
     2 
     3     public static void main(String[] args) {
     4         new TicketThread("窗口1").start();
     5         new TicketThread("窗口2").start();
     6         new TicketThread("窗口3").start();
     7         new TicketThread("窗口4").start();
     8     }
     9 
    10 }
    11 
    12 class TicketThread extends Thread {
    13 
    14     public TicketThread(String name) {
    15         super(name);
    16     }
    17 
    18     private static int ticket = 100;
    19 
    20     public void run() {
    21         while (true) {
    22             synchronized (TicketThread.class) {
    23                 if (ticket <= 0) {
    24                     break;
    25                 }
    26                 System.out.println(getName() + "卖出了第" + ticket-- + "张票!");
    27                 try {
    28                     Thread.sleep(100);
    29                 } catch (InterruptedException e) {
    30                     e.printStackTrace();
    31                 }
    32             }
    33         }
    34     }
    35 }

     

        • B 当传入的参数为1时,以下是代码演示和执行结果,这次执行的效果就不是很好,并不是每一个线程都能很好的执行到,或者执行得不是很分散。
     1 public class TicketsThreadTest {
     2 
     3     public static void main(String[] args) {
     4         new TicketThread("窗口1").start();
     5         new TicketThread("窗口2").start();
     6         new TicketThread("窗口3").start();
     7         new TicketThread("窗口4").start();
     8     }
     9 
    10 }
    11 
    12 class TicketThread extends Thread {
    13 
    14     public TicketThread(String name) {
    15         super(name);
    16     }
    17 
    18     private static int ticket = 100;
    19 
    20     public void run() {
    21         while (true) {
    22             synchronized (TicketThread.class) {
    23                 if (ticket <= 0) {
    24                     break;
    25                 }
    26                 System.out.println(getName() + "卖出了第" + ticket-- + "张票!");
    27                 try {
    28                     Thread.sleep(1);
    29                 } catch (InterruptedException e) {
    30                     e.printStackTrace();
    31                 }
    32             }
    33         }
    34     }
    35 }

     

     

        • C 总结以下时间参数对线程的结果的影响,以卖火车票为例,当我们在sleep方法中输入不同的参数,那么线程的运行结果就发生了变化,因为当我们给定的休眠期长了,那么线程的抢夺CPU执行权的速度就放缓了,此时运行的结果就变得比较分散,如果几乎没有休眠期那么抢到执行权的窗口(线程)可能还是处于领先优势,sleep方法其实让处于优先地位的暂时休眠让出了CPU执行权,然后sleep醒来又处于就绪状态来抢夺资源。这样不会让其他线程变成无法执行的尴尬境遇。当然后续可以使用wait和notify以及notifyAll的方法,让线程进行有规律地交替运行。

     

    <二>明确需要同步的共享资源

           如果这里同步的是代码块不是代码方法,那么这里需要对要同步的共享资源的选择要准确,如果选择得不准确会导致结果不理想。

        • A 以下代码表示选择的共享代码块为售票的单个输出语句,此时可以看出结果,结果出现了负票
     1 public class TicketsThreadTest {
     2 
     3     public static void main(String[] args) {
     4         new TicketThread("窗口1").start();
     5         new TicketThread("窗口2").start();
     6         new TicketThread("窗口3").start();
     7         new TicketThread("窗口4").start();
     8     }
     9 
    10 }
    11 
    12 class TicketThread extends Thread {
    13 
    14     public TicketThread(String name) {
    15         super(name);
    16     }
    17 
    18     private static int ticket = 100;
    19 
    20     public void run() {
    21         while (true) {
    22                 if (ticket <= 0) {
    23                     break;
    24                 }
    25                 synchronized (TicketThread.class) {
    26                 System.out.println(getName() + "卖出了第" + ticket-- + "张票!");
    27                 }
    28                 try {
    29                     Thread.sleep(0);
    30                 } catch (InterruptedException e) {
    31                     e.printStackTrace();
    32             }
    33         }
    34     }
    35 }

     

        • B 以下代码表示选择的共享代码块是while循环的整个代码块,此时可以看出结果,结果没有出现负票,而且经过了多次尝试也没有出现
     1 public class TicketsThreadTest {
     2 
     3     public static void main(String[] args) {
     4         new TicketThread("窗口1").start();
     5         new TicketThread("窗口2").start();
     6         new TicketThread("窗口3").start();
     7         new TicketThread("窗口4").start();
     8     }
     9 
    10 }
    11 
    12 class TicketThread extends Thread {
    13 
    14     public TicketThread(String name) {
    15         super(name);
    16     }
    17 
    18     private static int ticket = 100;
    19 
    20     public void run() {
    21         while (true) {
    22             synchronized (TicketThread.class) {
    23                 if (ticket <= 0) {
    24                     break;
    25                 }
    26                 System.out.println(getName() + "卖出了第" + ticket-- + "张票!");
    27                 try {
    28                     Thread.sleep(0);
    29                 } catch (InterruptedException e) {
    30                     e.printStackTrace();
    31                 }
    32             }
    33         }
    34     }
    35 }

     

        • C 总结在选择需要同步的代码块是一定要注意哪些代码块(资源是需要共享的),这里就要判断下这些代码是否是需要共享,将需要共享的资源用synchronized代码块包起来

     

    <三>线程通信之while和if的选择

        • A 以下的代码使用的是if选择结构进行线程通信之间的判断,可以发现三个线程之间没有有规律地交替进行。
      1 package javase.week4;
      2 
      3 /**
      4  * 
      5  * 三个线程之间的通信使用if选择语句
      6  *
      7  */
      8 public class ComunicatedThreadTest {
      9     public static void main(String[] args) {
     10         Printer1121 p = new Printer1121();
     11         new Thread() {
     12             @Override
     13             public void run() {
     14                 while (true) {
     15                     try {
     16                         p.print1();
     17                     } catch (Exception e) {
     18                         e.printStackTrace();
     19                     }
     20                 }
     21             }
     22         }.start();
     23         new Thread() {
     24             @Override
     25             public void run() {
     26                 while (true) {
     27                     try {
     28                         p.print2();
     29                     } catch (Exception e) {
     30                         e.printStackTrace();
     31                     }
     32                 }
     33             }
     34         }.start();
     35 
     36         new Thread() {
     37             @Override
     38             public void run() {
     39                 while (true) {
     40                     try {
     41                         p.print3();
     42                     } catch (Exception e) {
     43                         e.printStackTrace();
     44                     }
     45                 }
     46             }
     47         }.start();
     48     }
     49 
     50 }
     51 
     52 class Printer1121 {
     53     private int flag = 1;
     54 
     55     public void print1() throws Exception {
     56         synchronized (this) {
     57             if (flag != 1) {
     58                 this.wait();
     59             }
     60             Thread.sleep(100);
     61             System.out.print(1);
     62             System.out.print(2);
     63             System.out.print(3);
     64             System.out.print(4);
     65             System.out.print(5);
     66             System.out.println();
     67             flag = 2;
     68             this.notifyAll();
     69         }
     70     }
     71 
     72     public void print2() throws Exception {
     73         synchronized (this) {
     74             if (flag != 2) {
     75                 this.wait();
     76             }
     77             Thread.sleep(100);
     78             System.out.print("a");
     79             System.out.print("b");
     80             System.out.print("c");
     81             System.out.print("d");
     82             System.out.print("e");
     83             System.out.println();
     84             flag = 3;
     85             this.notifyAll();
     86         }
     87     }
     88 
     89     public void print3() throws Exception {
     90         synchronized (this) {
     91             if (flag != 3) {
     92                 this.wait();
     93             }
     94             Thread.sleep(100);
     95             System.out.print("A");
     96             System.out.print("B");
     97             System.out.print("C");
     98             System.out.print("D");
     99             System.out.print("E");
    100             System.out.println();
    101             flag = 1;
    102             this.notifyAll();
    103         }
    104     }
    105 }

     

        • B 以下是用while对通信条件进行循环判断的,可以发现三个线程是有规律地循环进行运行的。
      1 package javase.week4;
      2 /**
      3  * 
      4  * 三个线程之间的通信使用while循环判断语句
      5  *
      6  */
      7 public class ComunicatedThreadTest {
      8     public static void main(String[] args) {
      9         Printer1121 p = new Printer1121();
     10         new Thread() {
     11             @Override
     12             public void run() {
     13                 while (true) {
     14                     try {
     15                         p.print1();
     16                     } catch (Exception e) {
     17                         e.printStackTrace();
     18                     }
     19                 }
     20             }
     21         }.start();
     22         new Thread() {
     23             @Override
     24             public void run() {
     25                 while (true) {
     26                     try {
     27                         p.print2();
     28                     } catch (Exception e) {
     29                         e.printStackTrace();
     30                     }
     31                 }
     32             }
     33         }.start();
     34 
     35         new Thread() {
     36             @Override
     37             public void run() {
     38                 while (true) {
     39                     try {
     40                         p.print3();
     41                     } catch (Exception e) {
     42                         e.printStackTrace();
     43                     }
     44                 }
     45             }
     46         }.start();
     47     }
     48 
     49 }
     50 
     51 class Printer1121 {
     52     private int flag = 1;
     53 
     54     public void print1() throws Exception {
     55         synchronized (this) {
     56             while (flag != 1) {
     57                 this.wait();
     58             }
     59             Thread.sleep(100);
     60             System.out.print(1);
     61             System.out.print(2);
     62             System.out.print(3);
     63             System.out.print(4);
     64             System.out.print(5);
     65             System.out.println();
     66             flag = 2;
     67             this.notifyAll();
     68         } 
     69     }
     70 
     71     public void print2() throws Exception {
     72         synchronized (this) {
     73             while (flag != 2) {
     74                 this.wait();
     75             }
     76             Thread.sleep(100);
     77             System.out.print("a");
     78             System.out.print("b");
     79             System.out.print("c");
     80             System.out.print("d");
     81             System.out.print("e");
     82             System.out.println();
     83             flag = 3;
     84             this.notifyAll();
     85         }
     86     }
     87 
     88     public void print3() throws Exception {
     89         synchronized (this) {
     90             while (flag != 3) {
     91                 this.wait();
     92             }
     93             Thread.sleep(100);
     94             System.out.print("A");
     95             System.out.print("B");
     96             System.out.print("C");
     97             System.out.print("D");
     98             System.out.print("E");
     99             System.out.println();
    100             flag = 1;
    101             this.notifyAll();
    102         }
    103     }
    104 }

        • C 这里进行下原因分析,为什么会出现这样的情况?首先wait方法在同步代码块里被调用了,那么此时调用者直接在wait处等待了,然后等待下次被notify或者notifyAll唤醒。而if选择结构在判断一次之后就顺序执行了,当线程被唤醒时,我们希望的是再次判断一次条件看能够继续进行,但是if无法做到,因为上次已经判断正确了,它只会向下继续执行此时就会又出现随意无规律交替运行,但是while是循环判断,即使判断过一次了,但是每次执行完它会再次判断,这时就会让三个线程的运行结果有规律了。

     

    转载于:https://www.cnblogs.com/JNovice/p/9425361.html

    展开全文
  • 关于线程同步

    2019-07-23 13:27:41
    对于多线程同步锁,看了两天,自己总结了一些心得,希望对大家有点帮助,有错误的话,希望大神帮忙指一下. 一个类创建出来的对象是有两把锁的,一把是对象,一把是类. 所有非静态方法有synchronized,或者是非静态方法里面...
  • Resource类中的add()方法和sub()方法首先if判断flag状态,如果为true应该执行 this.wait()线程进入等待状态。如果为false执行else{}中的语句。按理说if(){}后的语句不用else{}扩起来应该不影响功能的实现,看...
  • 多线程编程是有趣的事情,它很容易突然出现“错误情况”,这是由于系统的线程调度具有一定的随机性造成的。不过,即使程序偶然出现...关于线程安全问题,有一个景点的问题:银行取钱的问题。银行取钱基本可以分为如下
  • 另外,能麻烦解释一下线程同步的具体概念吗? PS:上面的代码由于我为了缩短长度进行了移动,结果出现了语法错误,原本 ThreadFunc的函数体是放在main后面的,执行时是没有语法错误的,请放心
  • 今天在改一个程序,改成部分逻辑用lua写,这个程序是多线程的。将程序中部分逻辑改成lua之后,各种非法访问内存错误,各种奇奇怪怪的问题,不分时间,不... 前几天我转载的一篇文章,文章写了关于lua多线程的作法。...
  • 线程同步与线程通信 多线程是有趣的事情,它很容易突然出现”错误情况”,这是由于系统的线程调度具有一定的随机性造成的.不过,即使程序偶然出现问题,那么是由于编程不当所引起的.当使用多个线程来访问同一个数据时...
  • 多线程编程是有趣的事情,当常常容易突然出现“错误的情况”,这是由于系统的线程调度具有... 关于线程安全问题,有一个经典的问题:银行取钱问题。银行取钱的基本流程可以分为如下几个步骤: 【1】用户输入账...
  • 一个进程如果包含多个线程,并且这多个线程之间需要访问同一个对象是,就会涉及到多线程之间的同步,否者就会出现不可预料的错误。多线程之间同步可以采用互斥对象,事件对象,和关键代码段的方法。 互斥对象(mutex)...
  • 一、线程安全问题关于线程安全问题,有一个很经典的问题——银行取钱的问题。银行取钱的流程基本上可以分为如下几个步骤。①用户输入账户、密码,系统判别用户的账户、密码是否匹配 ②用户输入取款
  • 线程同步

    2015-12-07 22:07:41
    多线程编程时有趣的事情,它常常容易突然出现“错误情况”,这是...关于线程安全的问题,有一个经典的问题:银行取钱的问题。银行取钱的基本流程基本可以分为如下几个步骤: 1、用户输入账户、密码,系统判断用户的
  • 1线程同步 多线程编程是有趣的事情,它很容易突然出现“错误情况”,这是有系统的线程调度具有一定的随机性造成的,不过即使程序偶然出现问题,那也是由于编程不当引起的。当使用多个线程来访问同一个数据时,很容易...
  • **一:进程与线程的简单概念及理解** *对于所有需要等待的操作,...在VS编辑器中输入代码的时候,系统会分析代码,用下划线标注遗漏的分号和其他语法错误,这就是用一个后台线程完成。Word文档需要一个线程等待用...
  • Java线程同步笔记

    千次阅读 2009-03-30 19:48:00
    但有时会看到一些关于线程错误用法。下面列出一些应该注意的问题。 1.同步对象的恒定性 All java objects are references. 对于局部变量和参数来说,java里面的int, float, double, boolean等基本数据类型,都在...
  • Vc++中线程同步

    2009-11-20 14:06:00
    本文章小编带给大家的话题是关于Vc++中为什么要使用多线程,多线程的使用会产生一些新的问题,主要是如何保证线程同步执行。多线程应用程序需要使用同步对象和等待函数来实现同步。 由于同一进程的所有线程共享...
  • 多个线程同时访问共享数据时,会产生某些错误,例如数据不同步。所以使用线程锁是必要的。 一般应用于I/O操作较密集或者资源需要保持同步的场景中。 使用方法: 创建锁:lock = threading.Lock() 锁定代码:lock....
  • 关于线程的问题

    2014-09-13 21:51:00
    0.Java 中多线程同步是什么?  在多线程程序下,同步能控制对共享资源的访问。如果没有同步,当一个 Java 线程在修改一个共享变量时,另外一个线程正在使用或者更新同一个变量,这样容易导致程序出现错误的结果。 ...
  • 但有时会看到一些关于线程错误用法。下面列出一些应该注意的问题。 1.同步对象的恒定性All java objects are references. 对于局部变量和参数来说,java里面的int, float, double, boolean等基本数据类型,都在...
  • 关于线程常见问题

    2015-03-21 16:50:04
    如果没有同步,当一个线程在修改这个变量时,另一个线程在使用或更新同一个变量,这样容易导致程序出现错误结果。2.实现多线程的几种方法?Java线程可以通过实现Runnable接口或是继承Thread类来实现,若是打算多继承...
  • 关于多线程中的安全问题先说下这个安全问题产生的原因:1....所以就会产生了变量值被其他线程调用时数据不对,结果最终结果不对的错误采取的方法:采取线程同步,何为同步?就是协同步调,使线程有次序有顺序
  • 原文:根据前面对synchronized(this)同步代码块的作用总结可知,synchronized(非this对象)格式的作用只有一种:synchronized(非this对象x)同步代码块。  1)在多个线程持有“对象监视器”为同一个对象的前提...
  • 南京邮电大学操作系统——实验二:线程的互斥与同步前言编程题题目1 售票同步问题题目2 司机和售票员的同步过程关于吃橘子问题的异常输出及排查问题对应的错误输出 前言 由于本实验的大部分实验较为简单,所以这里只...
  • 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个参与进来执行,导致共享数据的错误 解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中...
  • 首先,为什么要同步,不同步出现错误的时机是什么?  还有,单例模式有懒汉式和非懒汉式,如果是懒汉式是否需要加同步锁,非懒汉式呢? 答案: 不同步的话, 对于懒汉式的, 就是在, 这个类的实例还没有...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 310
精华内容 124
关键字:

关于线程同步错误