线程-同步

 1 import java.util.*;
 2 public class thd implements Runnable
 3 {
 4     Timer timer = new Timer();
 5     public static void main(String args[])
 6     {
 7         thd td=new thd();
 8         Thread t1=new Thread(td);
 9         Thread t2=new Thread(td);
10         t1.setName("t1");
11         t2.setName("t2");
12         t1.start();
13         t2.start();
14     }
15     public void run()
16     {
17         timer.add(Thread.currentThread().getName());
18     }
19 }
20
21
22 class Timer
23 {
24     private static int num=0;
25     public void add(String name)
26     {
27         num++;
28         try
29         {
30             Thread.sleep(1);
31         }
32         catch(InterruptedException e)
33         {}
34             System.out.println(name+",你是第 "+num+"个使用timer的线程");
35     }
36 }

执行结果如下:

  t1,你是第 2个使用timer的线程
  t2,你是第 2个使用timer的线程

奇怪,为什么结果不是 t1,你是第1一个使用timer的线程呢?

原因是当第一个线程执行访问timer对象的add方法时,num(data 区域)变成了1,而此时t1线程休眠了,此时t2线程开始执行了,访问的也是同一个timer对象,所以num变成了2,此时线程t1睡醒了,开始打印num=2了,所以结果就成了出现的样子。

  我们如果想要的得到的结果,必须让num++ 和System.out.println(name+",你是第 "+num+"个使用timer的线程")成为一个原子性(不可再分)的执行过程,所以这时候线程同步就诞生了。

  下面是两种办法解决同步问题:

第一种:

 1  public void add(String name)
 2     {
 3         synchronized(this)
 4         {
 5             num++;
 6             try
 7             {
 8                 Thread.sleep(1);
 9             }
10             catch(InterruptedException e)
11             {
12
13             }
14             System.out.println(name+",你是第 "+num+"个使用timer的线程");
15         }
16     }

执行结果:

  t1,你是第 1个使用timer的线程
  t2,你是第 2个使用timer的线程

  synchronized(this){} 在括号中语句被一个线程访问时,不允许另外一个线程访问,这就是锁的机制,正是所谓的互斥锁。

第二种:

 1 synchronized public void add(String name)
 2     {
 3         num++;
 4         try
 5         {
 6             Thread.sleep(1);
 7         }
 8         catch(InterruptedException e)
 9         {
10
11         }
12         System.out.println(name+",你是第 "+num+"个使用timer的线程");
13     }

执行结果:

  t1,你是第 1个使用timer的线程
  t2,你是第 2个使用timer的线程

这叫做“在执行该方法过程中锁定当前对象”。

二.关于 synchronized(重要)

打个比方:一个object就像一个大房子,大门永远打开。房子里有很多房间(也就是方法)。这些房间有上锁的(synchronized方法)和不上锁之分(普通方法)。房门口放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。另外我把所有想调用该对象方法的线程比喻成想进入这房子某个房间的人。

  所有的东西就这么多了,下面我们看看这些东西之间如何作用的。在此我们先来明确一下我们的前提条件。该对象至少有一个synchronized方法。一个人想进入某间上了锁的房间,他来到房子门口,看见钥匙在那儿(说明暂时还没有其他人要使用上锁的房间)。于是他走上去拿到了钥匙,并且按照自己的计划使用那些房间。注意一点,他每次使用完一次上锁的房间后会马上把钥匙还回去。即使他要连续使用两间上锁的房间,中间他也要把钥匙还回去,再取回来。因此,普通情况下钥匙的使用原则是:“随用随借,用完即还。”这时其他人可以不受限制的使用那些不上锁的房间,一个人用一间可以,两个人用一间也可以,没限制。但是如果当某个人想要进入上锁的房间,他就要跑到大门口去看看了。有钥匙当然拿了就走,没有的话,就只能等了。要是很多人在等这把钥匙,等钥匙还回来以后,谁会优先得到钥匙?Not guaranteed。象前面例子里那个想连续使用两个上锁房间的家伙,他中间还钥匙的时候如果还有其他人在等钥匙,那么没有任何保证这家伙能再次拿到。

线程-同步

时间: 2024-10-27 05:37:17

线程-同步的相关文章

[.net]基元线程同步构造

1 /* 基元线程同步构造 2 用户模式构造: 3 易变构造(Volatile Construct) 4 互锁构造(Interlocked Construct):自旋锁(Spinlock) 乐观锁(Optimistic Concurrency Control,乐观并发控制) 5 内核模式构造: 6 事件构造(Event) 7 信号量构造(Semaphore) 8 互斥体构造(Mutex) 9 */ 10 11 //易变构造,Volatile.Write()之前的所有字段写入操作,必须再该方法调用

iOS多线程编程:线程同步总结 NSCondtion

1:原子操作 - OSAtomic系列函数 iOS平台下的原子操作函数都以OSAtomic开头,使用时需要包含头文件<libkern/OSBase.h>.不同线程如果通过原子操作函数对同一变量进行操作,可以保证一个线程的操作不会影响到其他线程内对此变量的操作,因为这些操作都是原子式的.因为原子操作只能对内置类型进行操作,所以原子操作能够同步的线程只能位于同一个进程的地址空间内. 2:锁 - NSLock系列对象 iOS平台下的锁对象为NSLock对象,进入锁通过调用lock函数,解锁调用unl

线程同步之EVENT

事件可传信给其他线程,表示某些条件现在已具备,比如有可用的消息. 事件可分为手动复位和自动复位,前者可传信给许多同时等待事件的线程而且可以被复位. 自动复位的事件传信给单个等待时间的线程,该事件会自动复位. Applications can use event objects in a number of situations to notify a waiting thread of the occurrence of an event. For example, overlapped I/O

【java并发】(2) Java线程同步:synchronized锁住的是代码还是对象

在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行.synchronized既可以加在一段代码上,也可以加在方法上. 关键是,不要认为给方法或者代码段加上synchronized就万事大吉,看下面一段代码: class Sync { public synchronized void test() { System.out.println("test开始.."); try { Thread.sle

Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会引起此共享资源的不一致性.因此,为避免线程安全问题,应该避免多线程环境下对此共享资源的并发访问. 线程安全问题多是由全局变量和静态变量引起的,当多个线程对共享数据只执行读操作,不执行写操作时,一般是线程安全的:当多个线程都执行写操作时,需要考虑线程同步来解决线程安全问题. 二.线程同步(synchr

系统API函数实现多线程及线程同步

1.线程的创建 须包含头文件:#include <windows.h> HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); lpThreadAttributes:指向SECURI

Java进击C#——语法之线程同步

上一章我们讲到关于C#线程方向的应用.但是笔者并没有讲到多线程中的另一个知识点--同步.多线程的应用开发都有可能发生脏数据.同步的功能或多或少都会用到.本章就要来讲一下关于线程同步的问题.根据笔者这几年来的.NET开发可以了解到的同步方式至少有四种以上.如.lock.volatile.Monitor等. lock方式 对lock的关键字作用跟JAVA的synchronized关键字类似.但有一定的差别.JAVA的synchronized关键字可能修饰在方法上面.可惜C#却不能修饰在方法上面.用法

经典线程同步 信号量Semaphore

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> <秒杀多线程第七篇经典线程同步互斥量Mutex> 前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore常用有三个函数,使用很方便.下面是这几个函数的原型和使

Linux系统开发9 线程同步

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <大纲> Linux系统编程8 线程同步 多线程共享资源,不加锁,同步互斥演示 多线程共享资源,加锁,同步互斥演示 读写锁:3个写线程,5个读线程,不加锁,并行处理 读写锁:3个写线程,5个读线程,加读写锁,串行处理 条件变量:生产消费者模型 信号量 进程间锁 文件锁: 习题 死锁,哲学家就餐 多线程共享资源,不加锁,同步互斥演示 [email protected]:~/linux_c/thread$ ca

线程同步方式比较

用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区. 内核模式下的方法有:事件,信号量,互斥量. 临界区 保证在某一时刻只有一个线程能访问数据的简便办法.在任意时刻只允许一个线程对共享资源进行访问.如果有多个线程试图同时访问临界区,那么 在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开.临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操 作共享资源的目的. 仅能在同一进程内使用 互斥量 Mutex 互斥量跟临界区很相似,只有拥有互