Java中利用synchronized关键字实现多线程同步问题

Java 中多线程的同步依靠的是对象锁机制,synchronized关键字就是利用了封装对象锁来实现对共享资源的互斥访问。

下面以一个简单例子来说明多线程同步问题,我们希望在run()方法里加入synchronized关键字来实现互斥访问。

package com.clark.thread;

public class MyThread implements Runnable{
    private int threadId;
    
    public MyThread(int id){
        this.threadId = id;
    }
    @Override
    public synchronized void run() {
        //此时关键字synchronized锁住的是this对象,即当前运行线程对象本身
        for (int i = 0; i < 100; i++) {
            if(i % 10 ==0){
                System.out.println();
            }
            System.out.print("Thread ID:"+this.threadId+":"+i+" ");
        }
    }

}

测试类:

package com.clark.thread;

public class ThreadDemo {
	public static void main(String[] args) throws InterruptedException {
                 //代码中创建了10个线程,而每个线程都持有this对象的对象锁,这不能实现线程的同步。
                 for (int i = 0; i < 10; i++) {
			new Thread(new MyThread(i)).start();
			Thread.sleep(1);
		 }
	}
}

打印结果部分如下:其线程不是互斥访问的。因此没有达到资源多线程同步效果。。。

Thread ID:1:60 Thread ID:1:61 Thread ID:1:62 Thread ID:1:63 Thread ID:1:64 Thread ID:1:65 Thread ID:1:66 Thread ID:1:67 Thread ID:1:68 Thread ID:1:69
Thread ID:1:70 Thread ID:1:71 Thread ID:1:72 Thread ID:1:73 Thread ID:1:74 Thread ID:1:75 Thread ID:1:76
Thread ID:1:77 Thread ID:1:78 Thread ID:1:79
Thread ID:1:80 Thread ID:1:81 Thread ID:2:0 Thread ID:1:82 Thread ID:1:83 Thread ID:1:84 Thread ID:1:85 Thread ID:1:86 Thread ID:1:87 Thread ID:1:88 Thread ID:1:89
Thread ID:1:90 Thread ID:1:91 Thread ID:1:92 Thread ID:1:93 Thread ID:1:94 Thread ID:1:95 Thread ID:2:1 Thread ID:2:2 Thread ID:2:3 Thread ID:2:4 Thread ID:2:5 Thread ID:2:6 Thread ID:2:7 Thread ID:2:8 Thread ID:2:9

从上述得知,要想实现线程同步,必须让这些线程去竞争一个唯一的共享对象锁。

package com.clark.thread;

public class MyThread implements Runnable{
	private int threadId;
	private Object object;//线程之间竞争使用的对象锁
	public MyThread(int id,Object object){
		this.threadId = id;
		this.object = object;
	}
	@Override
	public  void run() {
		/**
		 * 将这个object对象的引用传递给每一个线程对象的lock成员变量
		 * 从而每个线程的lock成员都指向同一个Object对象
		 * 这样就可以让线程去竞争这个唯一的共享的对象锁,从而实现同步。
		 */
		synchronized(object){
			for (int i = 0; i < 100; i++) {
				if(i % 10 ==0){
					System.out.println();
				}
				System.out.print("Thread ID:"+this.threadId+":"+i+" ");
			}
		}
	}

}
package com.clark.thread;

public class ThreadDemo {
	public static void main(String[] args) throws InterruptedException {
		Object obj = new Object();
		for (int i = 0; i < 10; i++) {
			new Thread(new MyThread(i,obj)).start();
			Thread.sleep(1);
		}
	}
}

测试结果如下:

Thread ID:5:60 Thread ID:5:61 Thread ID:5:62 Thread ID:5:63 Thread ID:5:64 Thread ID:5:65 Thread ID:5:66 Thread ID:5:67 Thread ID:5:68 Thread ID:5:69
Thread ID:5:70 Thread ID:5:71 Thread ID:5:72 Thread ID:5:73 Thread ID:5:74 Thread ID:5:75 Thread ID:5:76 Thread ID:5:77 Thread ID:5:78 Thread ID:5:79
Thread ID:5:80 Thread ID:5:81 Thread ID:5:82 Thread ID:5:83 Thread ID:5:84 Thread ID:5:85 Thread ID:5:86 Thread ID:5:87 Thread ID:5:88 Thread ID:5:89
Thread ID:5:90 Thread ID:5:91 Thread ID:5:92 Thread ID:5:93 Thread ID:5:94 Thread ID:5:95 Thread ID:5:96 Thread ID:5:97 Thread ID:5:98 Thread ID:5:99
Thread ID:6:0 Thread ID:6:1 Thread ID:6:2 Thread ID:6:3 Thread ID:6:4 Thread ID:6:5 Thread ID:6:6 Thread ID:6:7 Thread ID:6:8 Thread ID:6:9
Thread ID:6:10 Thread ID:6:11 Thread ID:6:12 Thread ID:6:13 Thread ID:6:14 Thread ID:6:15 Thread ID:6:16 Thread ID:6:17 Thread ID:6:18 Thread ID:6:19
Thread ID:6:20 Thread ID:6:21 Thread ID:6:22 Thread ID:6:23 Thread ID:6:24 Thread ID:6:25 Thread ID:6:26 Thread ID:6:27 Thread ID:6:28 Thread ID:6:29

从第二段代码可知,同步的关键是多个线程对象竞争同一个共享资源即可,上面的代码中是通过外部创建共享资源,然后传递到线程中来实现。我们也可以利用类成员变量被所有类的实例所共享这一特性,因此可以将lock用静态成员对象来实现,代码如下所示:修改MyThread.java类如下

package com.clark.thread;

public class MyThread implements Runnable{
	private int threadId;
	private static Object object = new Object();//线程之间竞争使用的对象锁
	public MyThread(int id){
		this.threadId = id;
	}
	@Override
	public  void run() {
		<strong>/**
		 * 将这个object对象的引用传递给每一个线程对象的lock成员变量
		 * 从而每个线程的lock成员都指向同一个Object对象
		 * 这样就可以让线程去竞争这个唯一的共享的对象锁,从而实现同步。
		 */</strong>
		synchronized(object){
			for (int i = 0; i < 100; i++) {
				if(i % 10 ==0){
					System.out.println();
				}
				System.out.print("Thread ID:"+this.threadId+":"+i+" ");
			}
		}
	}

}

结果如下:

Thread ID:0:0 Thread ID:0:1 Thread ID:0:2 Thread ID:0:3 Thread ID:0:4 Thread ID:0:5 Thread ID:0:6 Thread ID:0:7 Thread ID:0:8 Thread ID:0:9
Thread ID:0:10 Thread ID:0:11 Thread ID:0:12 Thread ID:0:13 Thread ID:0:14 Thread ID:0:15 Thread ID:0:16 Thread ID:0:17 Thread ID:0:18 Thread ID:0:19
Thread ID:0:20 Thread ID:0:21 Thread ID:0:22 Thread ID:0:23 Thread ID:0:24 Thread ID:0:25 Thread ID:0:26 Thread ID:0:27 Thread ID:0:28 Thread ID:0:29
Thread ID:0:30 Thread ID:0:31 Thread ID:0:32 Thread ID:0:33 Thread ID:0:34 Thread ID:0:35 Thread ID:0:36 Thread ID:0:37 Thread ID:0:38 Thread ID:0:39

再来看第一段代码,实例方法中加入sychronized关键字封锁的是this对象本身,而在静态方法中加入sychronized关键字封锁的就是类本身。静态方法是所有类实例对象所共享的,因此线程对象在访问此静态方法时是互斥访问的,从而可以实现线程的同步,代码如下所示:

package com.clark.thread;

public class MyThread implements Runnable{
	private int threadId;
	public MyThread(int id){
		this.threadId = id;
	}
	@Override
	public  void run() {
		start(this.threadId);
	}
	private static synchronized void start(int threadId2) {
		for (int i = 0; i < 100; i++) {
			if(i % 10 == 0){
				System.out.println();
			}
			System.out.print("Thread ID:"+threadId2+":"+i+" ");
		}
	}

}

结果如下=========

Thread ID:0:0 Thread ID:0:1 Thread ID:0:2 Thread ID:0:3 Thread ID:0:4 Thread ID:0:5 Thread ID:0:6 Thread ID:0:7 Thread ID:0:8 Thread ID:0:9 Thread ID:0:10 Thread ID:0:11
Thread ID:0:12 Thread ID:0:13 Thread ID:0:14 Thread ID:0:15 Thread ID:0:16 Thread ID:0:17 Thread ID:0:18 Thread ID:0:19 Thread ID:0:20 Thread ID:0:21 Thread ID:0:22 Thread ID:0:23 Thread ID:0:24 Thread ID:0:25 Thread ID:0:26 Thread ID:0:27 Thread ID:0:28 Thread
ID:0:29 Thread ID:0:30 Thread ID:0:31 Thread ID:0:32 Thread ID:0:33 Thread ID:0:34 Thread ID:0:35 Thread ID:0:36 Thread ID:0:37 Thread ID:0:38 Thread ID:0:39 Thread ID:0:40 Thread ID:0:41 Thread ID:0:42 Thread ID:0:43 Thread ID:0:44 Thread ID:0:45 Thread ID:0:46
Thread ID:0:47 Thread ID:0:48 Thread ID:0:49 Thread ID:0:50 Thread ID:0:51 Thread ID:0:52 Thread ID:0:53 Thread ID:0:54 Thread ID:0:55 Thread ID:0:56 Thread ID:0:57 Thread ID:0:58 Thread ID:0:59

时间: 2024-08-24 09:05:54

Java中利用synchronized关键字实现多线程同步问题的相关文章

JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程)把票陆陆续续的卖完了之后,我们要反思一下,这里面有没有安全隐患呢?在实际情况中,这种事情我们是必须要去考虑安全问题的,那我们模拟一下错误 package com.lgl.hellojava; import javax.security.auth.callback.TextInputCallback

巨人大哥谈Java中的Synchronized关键字用法

巨人大哥谈Java中的Synchronized关键字用法 认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方价格synchronized基本上就搞定 了,如果说不考虑性能问题的话,这一操绝对能应对百分之九十以上的情况,若对于性能方面有要求的话就需要额外的知识比如读写锁等等.本文目的先了解透彻synchronized的基本原理. Synchronized的基本使用 Synchronized的作用主要有三个: (1)确保线程互斥的访问同步代码 

Java中的Synchronized关键字用法

认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方加上synchronized修饰符基本上就搞定 了,如果说不考虑性能问题的话,这一招绝对能应对百分之九十以上的情况,若对于性能方面有要求的话就需要额外的知识比如读写锁等等.本文目的先了解透彻synchronized的基本原理. Synchronized的基本使用 Synchronized的作用主要有三个: (1)确保线程互斥的访问同步代码 (2)保证共享变量的修改能够及时可见 (3)有效解决

java中的synchronized关键字

参考:http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html 多线程问题的根因: 多线程环境下,对一个对象更改的时候,一个线程A对某个变量做了改变,但是还没改变完成能,就被另外一个线程B抢去了cpu,那么A就不会再执行了,因此导致了数据不一致行为.针对上面引文中银行取款存款的例子,本来存一百取一百正好抵消,但是由于多线程的之间的肆意抢占,有些取存款的操作没有完成,自然导致结果千奇百怪. 关键点: synchronized

谈谈java中的synchronized关键字

1.synchronized的3种用法 public class Client { public static void main(String[] args) { testSynchronized(); } private static void testSynchronized() { new Foo().sayHello(); } static class Foo { //修饰代码块 void sayHello() { synchronized (this) { System.out.pr

关于Java中的synchronized关键字

[内容简介] 本文主要介绍Java中如何正确的使用synchronized关键字实现线程的互斥锁. [能力需求] 至少已经完整的掌握了Java的语法基础,基本的面向对象知识,及创建并启动线程. [正文] 关于synchronized关键字的使用,很多说法是“锁同一个对象”就可以确保锁是正常的,今天,有人提了一个问题,我觉得非常不错,所以与各位一起分享一下. 在这里,就不提关于线程和synchronized关键字的基本使用了,以非常传统的“银行取钱”的故事为案例,直接上代码:Ps:以下代码是直接敲

详细讲解 java 中的synchronized 转自 http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html

Java synchronized详解 第一篇: 使用synchronized 在编写一个类时,如果该类中的代码可能运行于多线程环境下,那么就要考虑同步的问题.在Java中内置了语言级的同步原语 --synchronized,这也大大简化了Java中多线程同步的使用.我们首先编写一个非常简单的多线程的程序,是模拟银行中的多个线程同时对同一 个储蓄账户进行存款.取款操作的.在程序中我们使用了一个简化版本的Account类,代表了一个银行账户的信息.在主程序中我们首先生成了 1000个线程,然后启动

理解java中的volatile关键字

Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了 实现代码线程的安全性.Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分. volatile 写和读的内存语义: 线程 A 写一个 volatile 变量,实质上是线程 A

深入理解Java中的final关键字

Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使用final关键字的实例.final经常和static一起使用来声明常量,你也会看到final是如何改善应用性能的. final关键字的含义? final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如