1.对象锁:
1.1对象锁是run方法所在类的实例
synchronized 修饰非静态方法,或者 synchronized(this)时
public synchronized void method() { // todo }与
public void method(){synchronized(this) {// todo} }等价
1.1.1 结论:
当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
1.1.1示例说明:
public class ThreadTest implements Runnable{
public void run() {
method1();
}
private synchronized void method1(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj1,"线程2");
t1.start();
t2.start();
}
}
1.1.1执行结果:
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
1.1.2结论:当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块.
1.1.2示例说明:
public class ThreadTest implements Runnable{
public void run() {
if("线程1".equals(Thread.currentThread().getName())){
method1();
}else{
method2();
}
}
private synchronized void method1(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void method2(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj1,"线程2");
t1.start();
t2.start();
}
}
1.1.2执行结果:
线程1: 0
线程2: 0
线程1: 1
线程2: 1
线程2: 2
线程1: 2
线程1: 3
线程2: 3
线程1: 4
线程2: 4
1.1.3结论:
当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞
1.1.3示例代码:
更改1.1.2的method2方法,
在method2上添加synchronized
private synchronized void method2(){
//....
}
或者
private void method2(){synchronized(this){
//..
}}
1.1.3 执行结果
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
1.1.4结论:
多个线程访问不同的对象时,不会存在互斥的情况
1.1.4 示例代码:
将1.1.4 示例代码的main改为如下:(每个线程访问不同的对象)
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
ThreadTest obj2= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj2,"线程2");
t1.start();
t2.start();
}
1.1.4 执行结果
线程1: 0
线程2: 0
线程2: 1
线程1: 1
线程1: 2
线程2: 2
线程1: 3
线程2: 3
线程1: 4
线程2: 4
1.2 对象锁不是run方法所在类的实例
1.2.1 指定要给某个对象加锁
1.2.1 示例代码
class Account {
String name;
float amount;
public Account(String name, float amount) {
this.name = name;
this.amount = amount;
}
//存钱
public void deposit(float amt) {
amount += amt;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取钱
public void withdraw(float amt) {
amount -= amt;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public float getBalance() {
return amount;
}
}
class AccountOperator implements Runnable{
private Account account;
public AccountOperator(Account account) {
this.account = account;
}
public void run() {
synchronized (account) {
account.deposit(500);
account.withdraw(500);
System.out.println(Thread.currentThread().getName() + ":" + account.getBalance());
}
}
public static void main(String[] args) {
Account account = new Account("zhang san", 10000.0f);
AccountOperator accountOperator = new AccountOperator(account);
final int THREAD_NUM = 5;
Thread threads[] = new Thread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i ++) {
threads[i] = new Thread(accountOperator, "Thread" + i);
threads[i].start();
}
}
}
1.2.1 执行结果:
Thread0:10000.0
Thread4:10000.0
Thread3:10000.0
Thread2:10000.0
Thread1:10000.0
说明:account作为锁对象,起到了同步的效果
1.2.2 只是想让一段代码同步时,可以创建一个特殊的对象来充当锁:
创建 byte[] lock= new byte[0];比创建Object开销小,所以推荐byte[0]。
示例代码:
public class ThreadTest implements Runnable{
byte[] lock= new byte[0];
public void run() {
method2();
}
private void method2(){
synchronized (lock) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj1,"线程2");
t1.start();
t2.start();
}
}
执行结果:
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
说明:这种方式结果看似与private synchronized void method2(){//..}一致,但是synchronized (lock) 的锁是lock,而private synchronized void method2()锁是this。
1.2.3 静态的成员作为锁:
将示例1.2.2中byte[] lock= new byte[0]; 改为static byte[] lock= new byte[0];
这样,lock就只有一份,任何时候,最多一个线程进入到lock锁定的执行体
1.2.4 常量作为锁
public class ThreadTest2 implements Runnable{
public void run() {
method1();
}
private void method1(){
synchronized ("123") {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class ThreadTest implements Runnable{
public void run() {
method1();
}
private void method1(){
synchronized ("123") {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
ThreadTest2 obj2= new ThreadTest2();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj2,"线程2");
t1.start();
t2.start();
}
}
说明:常量作为锁,所有的用到这个常量的同步,都只能有一个线程能执行,不推荐
2.类锁:
synchronized 修饰静态方法 或者 synchronized(类名.class) { // todo}
public static synchronized void methodB() {
}
与
public void methodB() {
synchronized(所在类.class){
}
}
在多线程层面上来看,是等价的
示例2.1:
public class ThreadTest implements Runnable{
public void run() {
if("线程1".equals(Thread.currentThread().getName())){
method1();
}else{
method2();
}
}
private synchronized static void method1(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private synchronized static void method2(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
ThreadTest obj2= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj2,"线程2");
t1.start();
t2.start();
}
}
执行结果:
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
解释说明:
这里的锁是ThreadTest 类,所有对象共用这一把锁。
示例2.2
public class ThreadTest implements Runnable{
public void run() {
if("线程1".equals(Thread.currentThread().getName())){
method1();
}else{
method2();
}
}
private synchronized static void method1(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private synchronized void method2(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj1,"线程2");
t1.start();
t2.start();
}
}
执行结果:
线程1: 0
线程2: 0
线程2: 1
线程1: 1
线程2: 2
线程1: 2
线程1: 3
线程2: 3
线程1: 4
线程2: 4
解释说明:
因为method1的锁是ThreadTest 类,而method2的锁是当前对象(也就是这里的obj1),锁不同,不会互斥。
线程通俗描述:
一个object就像一个大房子,大门永远打开。房子里有 很多房间(也就是方法)。
这些房间有上锁的(synchronized方法), 和不上锁之分(普通方法)。房子外放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。所有想调用该对象方法的线程比喻成想进入这房子某个房间的人。第一个人进入房间后,房子外来了2个人,这两个人要等,第一个人从房间内出来,即使他还想去其他房间,也要把钥匙还回来,重新竞争。
1.1对象锁是run方法所在类的实例
synchronized 修饰非静态方法,或者 synchronized(this)时
public synchronized void method() { // todo }与
public void method(){synchronized(this) {// todo} }等价
1.1.1 结论:
当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
1.1.1示例说明:
public class ThreadTest implements Runnable{
public void run() {
method1();
}
private synchronized void method1(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj1,"线程2");
t1.start();
t2.start();
}
}
1.1.1执行结果:
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
1.1.2结论:当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块.
1.1.2示例说明:
public class ThreadTest implements Runnable{
public void run() {
if("线程1".equals(Thread.currentThread().getName())){
method1();
}else{
method2();
}
}
private synchronized void method1(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void method2(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj1,"线程2");
t1.start();
t2.start();
}
}
1.1.2执行结果:
线程1: 0
线程2: 0
线程1: 1
线程2: 1
线程2: 2
线程1: 2
线程1: 3
线程2: 3
线程1: 4
线程2: 4
1.1.3结论:
当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞
1.1.3示例代码:
更改1.1.2的method2方法,
在method2上添加synchronized
private synchronized void method2(){
//....
}
或者
private void method2(){synchronized(this){
//..
}}
1.1.3 执行结果
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
1.1.4结论:
多个线程访问不同的对象时,不会存在互斥的情况
1.1.4 示例代码:
将1.1.4 示例代码的main改为如下:(每个线程访问不同的对象)
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
ThreadTest obj2= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj2,"线程2");
t1.start();
t2.start();
}
1.1.4 执行结果
线程1: 0
线程2: 0
线程2: 1
线程1: 1
线程1: 2
线程2: 2
线程1: 3
线程2: 3
线程1: 4
线程2: 4
1.2 对象锁不是run方法所在类的实例
1.2.1 指定要给某个对象加锁
1.2.1 示例代码
class Account {
String name;
float amount;
public Account(String name, float amount) {
this.name = name;
this.amount = amount;
}
//存钱
public void deposit(float amt) {
amount += amt;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取钱
public void withdraw(float amt) {
amount -= amt;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public float getBalance() {
return amount;
}
}
class AccountOperator implements Runnable{
private Account account;
public AccountOperator(Account account) {
this.account = account;
}
public void run() {
synchronized (account) {
account.deposit(500);
account.withdraw(500);
System.out.println(Thread.currentThread().getName() + ":" + account.getBalance());
}
}
public static void main(String[] args) {
Account account = new Account("zhang san", 10000.0f);
AccountOperator accountOperator = new AccountOperator(account);
final int THREAD_NUM = 5;
Thread threads[] = new Thread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i ++) {
threads[i] = new Thread(accountOperator, "Thread" + i);
threads[i].start();
}
}
}
1.2.1 执行结果:
Thread0:10000.0
Thread4:10000.0
Thread3:10000.0
Thread2:10000.0
Thread1:10000.0
说明:account作为锁对象,起到了同步的效果
1.2.2 只是想让一段代码同步时,可以创建一个特殊的对象来充当锁:
创建 byte[] lock= new byte[0];比创建Object开销小,所以推荐byte[0]。
示例代码:
public class ThreadTest implements Runnable{
byte[] lock= new byte[0];
public void run() {
method2();
}
private void method2(){
synchronized (lock) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj1,"线程2");
t1.start();
t2.start();
}
}
执行结果:
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
说明:这种方式结果看似与private synchronized void method2(){//..}一致,但是synchronized (lock) 的锁是lock,而private synchronized void method2()锁是this。
1.2.3 静态的成员作为锁:
将示例1.2.2中byte[] lock= new byte[0]; 改为static byte[] lock= new byte[0];
这样,lock就只有一份,任何时候,最多一个线程进入到lock锁定的执行体
1.2.4 常量作为锁
public class ThreadTest2 implements Runnable{
public void run() {
method1();
}
private void method1(){
synchronized ("123") {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class ThreadTest implements Runnable{
public void run() {
method1();
}
private void method1(){
synchronized ("123") {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
ThreadTest2 obj2= new ThreadTest2();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj2,"线程2");
t1.start();
t2.start();
}
}
说明:常量作为锁,所有的用到这个常量的同步,都只能有一个线程能执行,不推荐
2.类锁:
synchronized 修饰静态方法 或者 synchronized(类名.class) { // todo}
public static synchronized void methodB() {
}
与
public void methodB() {
synchronized(所在类.class){
}
}
在多线程层面上来看,是等价的
示例2.1:
public class ThreadTest implements Runnable{
public void run() {
if("线程1".equals(Thread.currentThread().getName())){
method1();
}else{
method2();
}
}
private synchronized static void method1(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private synchronized static void method2(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
ThreadTest obj2= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj2,"线程2");
t1.start();
t2.start();
}
}
执行结果:
线程1: 0
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 0
线程2: 1
线程2: 2
线程2: 3
线程2: 4
解释说明:
这里的锁是ThreadTest 类,所有对象共用这一把锁。
示例2.2
public class ThreadTest implements Runnable{
public void run() {
if("线程1".equals(Thread.currentThread().getName())){
method1();
}else{
method2();
}
}
private synchronized static void method1(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private synchronized void method2(){
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+": "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadTest obj1= new ThreadTest();
Thread t1= new Thread(obj1,"线程1");
Thread t2= new Thread(obj1,"线程2");
t1.start();
t2.start();
}
}
执行结果:
线程1: 0
线程2: 0
线程2: 1
线程1: 1
线程2: 2
线程1: 2
线程1: 3
线程2: 3
线程1: 4
线程2: 4
解释说明:
因为method1的锁是ThreadTest 类,而method2的锁是当前对象(也就是这里的obj1),锁不同,不会互斥。
线程通俗描述:
一个object就像一个大房子,大门永远打开。房子里有 很多房间(也就是方法)。
这些房间有上锁的(synchronized方法), 和不上锁之分(普通方法)。房子外放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。所有想调用该对象方法的线程比喻成想进入这房子某个房间的人。第一个人进入房间后,房子外来了2个人,这两个人要等,第一个人从房间内出来,即使他还想去其他房间,也要把钥匙还回来,重新竞争。
发表评论
-
线程状态
2016-12-29 17:05 398线程在一定条件下,状 ... -
对java 多线程 wait notify notifyAll 的理解
2016-12-14 15:53 4273个人玩游戏一台手柄游戏,一次只能有一个人玩 示例代码1 ... -
compareTo
2016-12-09 16:24 427compareTo是按字典顺序比较两个字符串。该比较基于字符串 ... -
集合(放对象)排序
2016-12-09 15:37 420//转载:http://blog.csdn.net/zxy_s ... -
MyEclipse提示“错误: 找不到或无法加载主类”-转载
2016-07-18 10:44 1424转载:http://www.ithao123.cn/conte ... -
java复制的实现方式比较(clone,序列化)
2014-07-27 19:44 577java对象的复制 方式1:clone 所需操作:实现Clo ... -
集合的复制
2014-07-27 19:32 449//示例 //学生类 package com.softst ... -
数组的copy
2014-07-27 19:28 360package com.softstome.clone.arr ... -
深层复制与浅层复制(通过序列化的方式实现)
2014-07-27 19:23 867package com.softstome.clone.arr ... -
深层复制与浅层复制(通过clone的方式)
2014-07-27 19:12 761深层复制与浅层复制 深 ...
相关推荐
java中synchronized用法
java里面synchronized用法
java同步synchronized关键字用法示例
Java-synchronized详解.docx
java_synchronized详解 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。本文给大家介绍java中 synchronized的用法,对本文感兴趣的朋友一起看看吧
Java多线程synchronized关键字详解(六)共5页.pdf.zip
synchronized关键字在java中的重要性 以及常用的方法 还有它的详解
本文档主要讲述的是java synchronized详解;Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
java锁机制Synchronized java锁机制Synchronized java锁机制Synchronized java锁机制Synchronized
它可以确保在同一时刻,只有一个线程能够访问被synchronized修饰的代码块或方法。这种机制可以有效地避免多线程环境下的数据竞争和不一致问题。 在Java中,锁膨胀(Lock Inversion)是一个重要的概念。当一个对象被多...
本篇文章主要介绍了java synchronized用法详解,synchronized是Java中的关键字,是一种同步锁。有兴趣的同学可以了解一下。
javasynchronized详解.pdf
主要介绍了Java 同步锁(synchronized)详解及实例的相关资料,需要的朋友可以参考下
主要介绍了Java中synchronized实现原理详解,涉及synchronized实现同步的基础,Java对象头,Monitor,Mark Word,锁优化,自旋锁等相关内容,具有一定借鉴价值,需要的朋友可以参考下。
java中synchronized的使用,java中的锁锁的到底是什么?是括号里的代码块吗?肯定不是的;
java synchronized详解
synchronized同步锁(悲观锁)2.1 synchronized 作用范围2.2 synchronized 核心组件2.3 synchronized 实现 1. Java锁的种类 1.1 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低。 每次去拿...
java synchronized的一些小实验,对帮助理解synchronized的使用有一定的帮助。