为什么要考虑线程同步,当几个线程共享一份资源时会出现线程冲突。例如生产情景下,生产的物质正在放入共享区域时此时又一个线程要读取共享区域物质的个数此时就会出现冲突。线程同步实质是给线程进行排队。
看下面一个例子
Callme的同一实例传给每个Caller实例。
// This program is not synchronized.
class Callme {
void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println("]");
}
}
class Caller implements Runnable {
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s) {
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
public void run() {
target.call(msg);
}
}
class Synch {
public static void main(String args[]) {
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello");
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
// wait for threads to end
try {
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
}
}
该程序的输出如下:
Hello[Synchronized[World]
]
]
Thread.sleep(2000);表示此线程要做好多事比较耗时,故用此方法来表示。
就像上面输出的结果一样,线程对Callme的操作是无序的,当第一个线程没有执行完毕时第二个线程就进入了。
我们要输出一下效果:
[Hello]
[Synchronized]
[World]
就要解决线程同步的问题,解决线程同步问题有很多方法。
Synchronized 是一种方法,此方法可分为同步代码块和同步方法。本次我们将使用同步方法,和同步代码块实现一下。
同步方法:在call()方法前加入Synchronized。
代码如下:
public static void main(String[] args) {
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello");
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
// wait for threads to end
try {
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
}
// This program is not synchronized.
static class Callme {
synchronized void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println("]");
}
}
static class Caller implements Runnable {
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s) {
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
public void run() {
target.call(msg);
}
}
最后运行结果就如上面所说的。
同步代码块:在target.call(msg)方法外加上synchronize并用{}括起来。运行效果和上面的一样。
// synchronize calls to call()
public void run() {
synchronized(target) { // synchronized block
target.call(msg);
}
}
}
以上就是我为什么要使用同步线程,还有实现同步线程的此种方法法。
不知道大家有没有发现同步方法中启动线程的顺序是obj1 obj2 obj3
Caller ob1 = new Caller(target, "Hello");
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
而输出顺序则是hello world synchronized ,请看https://segmentfault.com/a/1190000013512810讲的 非公平锁/公平锁