说明:参考《Java多线程核心技术》
7、同步代码块
synchronized方法时对当前对象进行加锁,二synchronized代码块是对某一个对象进行加锁。
当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块后才能执行该代码块。
public class ThreadA extends Thread{
private SynchronizedThread synchronizedThread;
public ThreadA(SynchronizedThread synchronizedThread){
super();
this.synchronizedThread = synchronizedThread;
}
@Override
public void run(){
synchronizedThread.synchronizedService();
}
}
public class ThreadB extends Thread{
private SynchronizedThread synchronizedThread;
public ThreadB (SynchronizedThread synchronizedThread){
super();
this.synchronizedThread = synchronizedThread;
}
@Override
public void run(){
synchronizedThread.synchronizedService();
}
}
public class SynchronizedThread {
public void synchronizedService() {
try {
synchronized (this){
System.out.println(Thread.currentThread().getName() + " start time = " + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " end time = " + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class SynchronizedServiceTest {
public static void main(String[] args) {
SynchronizedThread thread = new SynchronizedThread();
ThreadA threadA = new ThreadA(thread);
threadA.start();
ThreadB threadB = new ThreadB(thread);
threadB.start();
}
}
/**
Thread-0 start time = 1546672500997
Thread-0 end time = 1546672503012
Thread-1 start time = 1546672503012
Thread-1 end time = 1546672505025
*/
从结果可以看出,只有当线程0结束后释放持有的锁时,线程1才能进入进行运行。注意,和synchronized方法一样,当一个线程方法一个synchronized同步代码块时,另一个线程在同时一人可以方法此对象中的非synchronized(this)同步代码块。synchronized方法和synchd同步代码块都是锁定当前对象。
8、将任意对象作为对象监视器
多个线程在调用同一个对象中的不同名称的synchronized同步方法或者synchronized(this)代码块时,调用的接收时按照顺序实行的,即同步的,阻塞的。
说明了synchronized同步方法或者synchronized(this)代码块分别有两种作用:
1、synchronized同步方法:
(1) 对其他synchronized方法或者synchronized(this)同步代码块的调用成阻塞状态。
(2)同一时间只有一个线程可以执行synchronized同步方法中的代码
2、synchronized(this)同步代码块
(1) 对其他synchronized方法或者synchronized(this)同步代码块的调用成阻塞状态。
(2)同一时间只有一个线程可以执行synchronized(this)同步代码中的代码
public class ThreadA extends Thread{
private AnyObjcetToSynch anyObjcetToSynch;
public ThreadA(AnyObjcetToSynch anyObjcetToSynch){
super();
this.anyObjcetToSynch = anyObjcetToSynch;
}
@Override
public void run(){
anyObjcetToSynch.setUserNamePassWord("a", "aa");
}
}
public class ThreadB extends Thread{
private AnyObjcetToSynch anyObjcetToSynch;
public ThreadB (AnyObjcetToSynch anyObjcetToSynch){
super();
this.anyObjcetToSynch = anyObjcetToSynch;
}
@Override
public void run(){
anyObjcetToSynch.setUserNamePassWord("b", "bb");
}
}
public class AnyObjcetToSynch {
private String userName;
private String passWord;
private String anyString = new String();
public void setUserNamePassWord (String userName, String passWord) {
try {
synchronized (anyString) {
System.out.println(Thread.currentThread().getName() + " start time = " + System.currentTimeMillis());
userName = userName;
Thread.sleep(1000);
passWord = passWord;
System.out.println(Thread.currentThread().getName() + " end time = " + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class AnyObjcetToSynchTest {
public static void main(String[] args) {
AnyObjcetToSynch thread = new AnyObjcetToSynch();
ThreadA threadA = new ThreadA(thread);
threadA.setName("A");
threadA.start();
ThreadB threadB = new ThreadB(thread);
threadB.setName("B");
threadB.start();
}
}
/**
A start time = 1546675670548
A end time = 1546675671562
B start time = 1546675671562
B end time = 1546675672576
*/
说明:锁为this具有一定的有点:如果一个累赘红有许多的synchronized方法,这时候虽然能实现同步,但是会受到阻塞。所以影响运行的效率。但是如果使用同步代码块非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与起亚锁this同步方法争抢this锁,可以较大的提升运行效率。
9、String的常量池特性
public class ThreadA extends Thread{
private StringParams stringParams;
public ThreadA(StringParams stringParams){
super();
this.stringParams = stringParams;
}
@Override
public void run(){
StringParams.print("AA");
}
}
public class ThreadB extends Thread{
private StringParams stringParams;
public ThreadB (StringParams stringParams){
super();
this.stringParams = stringParams;
}
@Override
public void run(){
StringParams.print("AA");
}
}
public class StringParams {
public static void print(String stringParams) {
try {
synchronized (stringParams) {
while (true) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class StringParamsTest {
public static void main(String[] args) {
StringParams thread = new StringParams();
ThreadA threadA = new ThreadA(thread);
threadA.start();
ThreadB threadB = new ThreadB(thread);
threadB.start();
}
}
/** 死循环
Thread-0
Thread-0
Thread-0
Thread-0
*/
说明:发生此现象的问题在于:两个线程持有相同的锁,造成线程B不能执行。由于String类型在常量池中具有缓存作用,它们两个共用用一个String常量。一般情况下,我们不用String作为锁对象,而是改用其他的,比如:new Object()实例化一个即可。