SyncThread用法

在多线程程序中,难免会多个线程操纵一个共享变量,以模拟多个窗口共同售票为例:

public class Demo {
    private int num=10;
    //未加synchronized修饰的sell方法
    public synchronized void sell(){
        if(num==0){
            return;
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+num+"张");
    }
    class window implements Runnable{

        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(true){
                sell();
                try {
                    Thread.sleep(1000*2);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        
    }
    public static void main(String[] args) {
        Demo d = new Demo();
        window w = d.new window();
        new Thread(w,"窗口1").start();
        new Thread(w,"窗口2").start();
        new Thread(w,"窗口3").start();
        new Thread(w,"窗口4").start();
        
    }

输出结果:

窗口1卖出一张票,剩余6张

窗口4卖出一张票,剩余7张

窗口3卖出一张票,剩余8张

窗口2卖出一张票,剩余5张

窗口4卖出一张票,剩余3张

窗口3卖出一张票,剩余3张

窗口1卖出一张票,剩余4张

窗口4卖出一张票,剩余1张

窗口1卖出一张票,剩余0张

窗口2卖出一张票,剩余1张

窗口3卖出一张票,剩余1张

很明显这不是我们想要的结果 导致这种结果的原因就是没有对sell方法加锁造成的

举个例子,int i=10; 开启两个进程 进程1和进程2 同时执行i=i-1操作并输出,

假设进程1先开始运行

进程1运行过程中,首先会先把i读取到内存当中,然后cpu从内存中读取i,执行i-1,最后将结果i=9刷新到内存中. 在整个过程中,某一时间段(cpu进行计算后,将结果返回内存前)存在两个i值,即内存中i=10 cpu中i=9;

这个时候若进程2读取i的值,读取的是内存中i的值 10,并不是进程1操作了i的结果值 9,因为此时进程1还未将计算结果刷新到内存;这便导致了明明执行了两次i-1操作结果却i=9;

为了避免这种情况,我们要对sell方法加锁(synchronized)

打个比方,一群人(多线程)去参观一座庄园(一个实体类的对象),里面有很多房子(方法),有的房子有锁(加了synchronized关键字),有的无锁(未加synchronized关键字),无锁的房子可随意由大家参观,而有锁的房子在门口放了把钥匙,当有人(进程)想进入房间(执行该方法),他首先会用钥匙打开房门然后带着钥匙进入房间,这样便不会有人进去打扰他参观,当他参观完后
走出房间将钥匙放在外面留给下一个想要参观的人
(需要执行该方法的其他进程).

如此便避免了多个线程对共享资源操作发生冲突

让我们看一下synchronized修饰了方法之后的运行结果

    //加了synchronized修饰的sell方法
    public synchronized void sell(){
        if(num==0){
            return;
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+num+"张");
    }

运行结果:

窗口1卖出一张票,剩余9张

窗口4卖出一张票,剩余8张

窗口3卖出一张票,剩余7张

窗口2卖出一张票,剩余6张

窗口3卖出一张票,剩余5张

窗口2卖出一张票,剩余4张

窗口4卖出一张票,剩余3张

窗口1卖出一张票,剩余2张

窗口4卖出一张票,剩余1张

窗口2卖出一张票,剩余0张

这才是我们想要的结果;

synchronized如果用来修饰方法,作用范围则是调用这个方法的对象 若按照下述方法开启进程 则依然是错误的结果
<pre name="code" class="java">public static void main(String[] args) {
		Demo d = new Demo();
		new Thread(d.new window(),"窗口1").start();
		new Thread(d.new window(),"窗口2").start();
		new Thread(d.new window(),"窗口3").start();
		new Thread(d.new window(),"窗口4").start();

	}

原因便是在开启线程时 每一次都new了一个window对象,这相当于是四个对象的四个进程,有四把锁,所以这样开启线程加不加synchronized修饰方法都是一样的

				
时间: 2024-10-29 16:08:49

SyncThread用法的相关文章

Java中Synchronized的用法

版权声明:本文为博主原创文章,未经博主允许不得用于任何商业用途,转载请注明出处. 目录(?)[+] 原文:http://blog.csdn.net/luoweifu/article/details/46613015 作者:luoweifu 转载请标名出处 <编程思想之多线程与多进程(1)--以操作系统的角度述说线程与进程>一文详细讲述了线程.进程的关系及在操作系统中的表现,这是多线程学习必须了解的基础.本文将接着讲一下Java线程同步中的一个重要的概念synchronized. synchro

synchronized的用法

synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象: 2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象: 3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象: 4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类

(7) Java中Synchronized的用法

synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象: 2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象: 3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象: 4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类

java中synchronized关键字的用法

在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁.获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法. java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A

synchronized的四种用法

一 修饰方法  Synchronized修饰一个方法很简单,就是在方法的前面加synchronized,synchronized修饰方法和修饰一个代码块类似,只是作用范围不一样,修饰代码块是大括号括起来的范围,而修饰方法范围是整个函数. 例如: 方法一 public synchronized void method() { // todo } 方法二 public void method() { synchronized(this) { // todo } } 写法一修饰的是一个方法,写法二修饰

js中获取时间new date()的用法

js中获取时间new date()的用法 获取时间:   var myDate = new Date();//获取系统当前时间 获取特定格式的时间: 1 myDate.getYear(); //获取当前年份(2位) 2 myDate.getFullYear(); //获取完整的年份(4位,1970-????) 3 myDate.getMonth(); //获取当前月份(0-11,0代表1月) 4 myDate.getDate(); //获取当前日(1-31) 5 myDate.getDay();

20.5 Shell脚本中的逻辑判断;20.6 文件目录属性判断;20.7 if特殊用法;20.8 20.9 cace判断(上下)

扩展: select用法 http://www.apelearn.com/bbs/thread-7950-1-1.html 20.5 Shell脚本中的逻辑判断 格式1:if 条件 ; then 语句; fi 1. 创建if1.sh测试脚本: [[email protected] ~]# vi if1.sh a=5,如果a大于3,满足这个条件,显示ok 添加内容: #!/bin/bash a=5 if [ $a -gt 3 ] then echo ok fi 2. 执行if1.sh脚本: [[e

20.1 Shell脚本介绍;20.2 Shell脚本结构和执行;20.3 date命令用法;20.4 Shell脚本中的变量

20.1 Shell脚本介绍 1. shell是一种脚本语言 aming_linux blog.lishiming.net 2. 可以使用逻辑判断.循环等语法 3. 可以自定义函数 4. shell是系统命令的集合 5. shell脚本可以实现自动化运维,能大大增加我们的运维效率 20.2 Shell脚本结构和执行 1. 开头(首行)需要加: #!/bin/bash 2. 以#开头的行作为解释说明: 3. 脚本的名字以.sh结尾,用于区分这是一个shell脚本 4. 执行.sh脚本方法有两种:

shell 中seq的用法 echo -n用法

用法:seq [选项]... 尾数 或:seq [选项]... 首数 尾数 或:seq [选项]... 首数 增量 尾数 从1循环到100的两种方法(bash 其它的shell没试过)for x in `seq 1 100`;do echo $x;donefor x in {1..100};do echo $x;done echo -n 不换行输出 $echo -n "123" $echo "456" 最终输出 123456 echo -e 处理特殊字符 若字符串中