一、synchronized
同步关键字,分为同步代码块和同步函数
二、对synchronized的理解(未加static关键字)(以下所说:对同步方法和同步代码块均适用)
对象的创建是以类为模板的
1、两个并发的线程访问同一个类Object中的synchronized(this)同步代码块或者同步方法时,同一时间只能执行一个,另一个必须要等待当前线程执行完才能执行(同一个对象:见下面的testSynchronized,分为两个线程,两个线程访问的是一个方法)(一个对象两个线程一个方法)
例子:
public class TestSynchronized {
public void test1(){
synchronized(this) {
System.out.println("1"+this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
final TestSynchronized testSynchronized1 = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testSynchronized.test1();
}
},"test1");
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
testSynchronized.test1();
}
},"test3");
thread1.start();
thread3.start();
}
}
结果:
2、两个并发的线程访问同一个类Object中的synchronized(this)同步代码块或者同步方法时,两个交替进行,因为对象的创建是以类为模板的,所以两个对象都会有自己独立的方法(不同对象:testSynchronized和testSynchronized1,分为两个线程,两个线程访问的是一个方法)(两个对象两个线程一个方法)
例子:和第一个的例子相比仅仅修改了第31行
public class TestSynchronized {
public void test1(){
synchronized(this) {
System.out.println("1"+this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
final TestSynchronized testSynchronized1 = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testSynchronized.test1();
}
},"test1");
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
testSynchronized1.test1();
}
},"test3");
thread1.start();
thread3.start();
}
}
复制代码
结果:
3、(两个线程同一对象)当一个线程已经访问了该类中的一个synchronized方法,另一个线程就不能再去访问访问其他的synchronized方法(对象锁是锁住了对象,所以只能执行完这个再去执行另一个)(一个对象两个线程两个方法)
例子:
public class TestSynchronized {
public void test1(){
synchronized(this) {
System.out.println("1"+this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public synchronized void test2(){
System.out.println(this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
final TestSynchronized testSynchronized1 = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testSynchronized.test1();
}
},"test1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
testSynchronized.test2();
}
},"test2");
thread1.start();
thread2.start();
}
}
结果:
4、(同一个对象)当一个线程已经访问了一个类的synchronized方法,那么另一个线程也可以访问其他的非synchronized方法,结果是交替进行的(一个对象两个线程两个方法[一个synchronized一个非synchronized的])
进行了同步的方法(加锁方法)和没有进行同步的方法(普通方法)是互不影响的,一个线程进入了同步方法,得到了对象锁,其他线程还是可以访问那些没有同步的方法(普通方法)
例子:
public class TestSynchronized {
public void test1(){
synchronized(this) {
System.out.println("1"+this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//非synchronized
public void test2(){
System.out.println(this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
final TestSynchronized testSynchronized1 = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testSynchronized.test1();
}
},"test1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
testSynchronized.test2();
}
},"test2");
thread2.start();
thread1.start();
}
}
结果:
三、加了static后现成的执行
1、对于一个类,一个线程访问了加了static的synchronized方法,另一个线程同样可以访问未加static的synchronized方法,所以结果是交替进行,因为类和对象不同(static修饰后锁住的是类,所有对象共享,而没有加static锁住的是对象,只有每个对象私有)(一个对象一个类两个线程两个方法)
例子:
public class TestSynchronized {
public void test1(){
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static synchronized void test2(){
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
//对象调用的是该对象自己的方法
testSynchronized.test1();
}
},"test1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
//类调用的是类方法
TestSynchronized.test2();
}
},"test2");
thread2.start();
thread1.start();
}
}
结果:
2、两个都是被static修饰的synchronized方法,结果是一个线程等待另一个线程执行完才会执行,因为类是一样的(和同一个对象的理解差不多),方法被synchronized修饰只能一个执行完再执行另一个(一个类两个线程两个方法)
例子:
public class TestSynchronized {
public static void test1(){
synchronized(TestSynchronized.class) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static synchronized void test2(){
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
TestSynchronized.test1();
}
},"test1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
TestSynchronized.test2();
}
},"test2");
thread2.start();
thread1.start();
}
}
结果:
补充:
面试的一道题:
一个只被synchronized修饰的方法fun(),现有两个对象a,b,分别是两个线程t1,t2
①a.fun()和b.fun()可以同时进行吗?
答:可以,因为是两个为不同的对象,对象的创建是以类为模板的,所以这两个对象中都会有自己的fun()方法,所以两个线程开启后会交替进行,如上面的二2
②回答完可以后,怎么可以让两个分开进行即一个完了之后再进行另一个?
答:给方法加上static关键字,static锁住了类,此时锁为“类锁”,所以虽然对象不一样但是类都是一样的,所以简单说就是一个类两个线程调用一个方法,肯定是一个执行完再执行另一个