我之前写过一篇synchronized的文章,在那篇文章中,我说
解决方法在函数上加锁。
试过
public synchronized void function{
//代码块
}
试过
public void function{
synchronized(this){
//代码块
}
}
结果都是两个线程同时执行代码块。
正确方法:
class A
{
public void function{
synchronized(A.class)
{
//代码块
}
}
}
额,发现synchronized(A.class)解决了我的问题,就说它是对的,别的是不对,真是大错特错。今天研读了synchronized的相关文章,来详细写下记录。
我自https://blog.csdn.net/luoweifu/article/details/46613015大牛处学习。
先从代码上记录synchronized的使用方式。
第一种
synchronized(this){
//代码块
}
第二种
synchronized(class) {
//代码块
}
第三种
public synchronized void function() {
//代码块
}
第四种
public synchronized static void function() {
//代码块
}
这四种的使用场景以及作用下面开始介绍。
一和三作用的对象是调用这个代码块的对象。
二和四作用的对象是这个类的所有的对象。
代码举例说明:
一、第一种测试类对四种synchronized用法的结果。
package test;
public class ThreadTest {
public static void main(String args[]) {
ThreadSync syncThread = new ThreadSync();
Thread thread1 = new Thread(syncThread, "SyncThread1");
Thread thread2 = new Thread(syncThread, "SyncThread2");
thread1.start();
thread2.start();
}
}
//因为只new了一个对象,所以对四种情况的结果预测是都线程同步
1、第一种 synchronized(this){//代码块}
package test;
public class ThreadSync implements Runnable{
public void run() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:0
SyncThread2:1
SyncThread2:2
SyncThread2:3
SyncThread2:4
结果:同步锁,线程同步。
2、第二种 synchronized(class){//代码块}
package test;
public class ThreadSync implements Runnable{
public void run() {
synchronized(ThreadSync.class) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
SyncThread2:0
SyncThread2:1
SyncThread2:2
SyncThread2:3
SyncThread2:4
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
结果:同步锁,线程同步。
3、第三种 public synchronized void function() {//代码块}
package test;
public class ThreadSync implements Runnable{
public synchronized void run() {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
SyncThread2:0
SyncThread2:1
SyncThread2:2
SyncThread2:3
SyncThread2:4
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
结果:同步锁,线程同步。
4、第四种 public synchronized static void function() {//代码块}
package test;
public class ThreadSync implements Runnable{
public void run() {
function();
}
public synchronized static void function() {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
SyncThread2:0
SyncThread2:1
SyncThread2:2
SyncThread2:3
SyncThread2:4
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
结果:同步锁,线程同步。
结论:如果是单个对象访问被修饰的方法或者代码块,都可以实现同步锁。
二、第二种测试类对四种synchronized用法的结果。
package test;
public class ThreadTest {
public static void main(String args[]) {
ThreadSync syncThread1 = new ThreadSync();
ThreadSync syncThread2 = new ThreadSync();
Thread thread1 = new Thread(syncThread1, "SyncThread1");
Thread thread2 = new Thread(syncThread2, "SyncThread2");
thread1.start();
thread2.start();
}
}
//因为只new了两个对象,所以对四种情况的结果预测是第一种和第三种不同步,第二种和第四种同步
1、第一种 synchronized(this){//代码块}
package test;
public class ThreadSync implements Runnable{
public void run() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
SyncThread2:0
SyncThread1:0
SyncThread2:1
SyncThread1:1
SyncThread2:2
SyncThread1:2
SyncThread1:3
SyncThread2:3
SyncThread1:4
SyncThread2:4
结果:同步锁不成功,线程不同步,各走各的。
2、第二种 synchronized(class){//代码块}
package test;
public class ThreadSync implements Runnable{
public void run() {
synchronized(ThreadSync.class) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
SyncThread2:0
SyncThread2:1
SyncThread2:2
SyncThread2:3
SyncThread2:4
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
结果:同步锁,线程同步。
3、第三种 public synchronized void function() {//代码块}
package test;
public class ThreadSync implements Runnable{
public synchronized void run() {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
SyncThread1:0
SyncThread2:0
SyncThread1:1
SyncThread2:1
SyncThread2:2
SyncThread1:2
SyncThread1:3
SyncThread2:3
SyncThread2:4
SyncThread1:4
结果:同步锁不成功,线程不同步,各走各的。
4、第四种 public synchronized static void function() {//代码块}
package test;
public class ThreadSync implements Runnable{
public void run() {
function();
}
public synchronized static void function() {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
SyncThread2:0
SyncThread2:1
SyncThread2:2
SyncThread2:3
SyncThread2:4
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
结果:同步锁,线程同步。
结论:如果是一个类的多个对象访问被修饰的方法或者代码块,修饰静态方法的方式和修饰类的方式可以实现同步锁,保证只有多个对象只有单个线程进入方法体。修饰普通方法的方式和修饰对象的方式只能锁住单个对象。
这里从大牛的博客里摘抄一个知识点。
当有一个明确的对象作为锁时,就可以用类似下面这样的方式写程序。
public void method3(SomeObject obj)
{
//obj 锁定的对象
synchronized(obj)
{
// todo
}
}
当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的对象来充当锁:
class Test implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance变量
public void method()
{
synchronized(lock) {
// todo 同步代码块
}
}
public void run() {
}
}
---------------------
作者:luoweifu
来源:CSDN
原文:https://blog.csdn.net/luoweifu/article/details/46613015
版权声明:本文为博主原创文章,转载请附上博文链接!
说明:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。