文章目录
synchronized
synchronized关键字:同步, 反义词 asynchronized 异步
同步资源,同步锁
-
此关键字可以修饰在方法上
比如:
public synchronized void method(){
//代码块
}
当线程1调用method方法时,就会给method方法添加一个锁
如果方法不执行完毕,其他线程就不会执行此代方法,线程排队等待 -
此关键字修饰在对象上
比如:
synchronized(某个对象){
//同步代码块
}
当线程1执行同步代码块时,就会给同步代码块添加一个锁
如果代码块不执行完毕,其他线程就不会执行此代码块,线程排队等待 -
此关键字修饰在类上
比如 :
synchronized (类名.class){
//同步代码块}
当线程1执行同步代码块时,就会给类添加一个锁
如果代码块不执行完毕,其他线程就不会执行此代码块,线程排队等待下面来具体介绍
synchronized同步方法测试
案例一
synchronized作用在同一个实例对象(test)上,
两个线程,一个线程调用synchronized修饰的方法,另一个调用普通的方法
public class SynchronizedTest1 {
public synchronized void methodA(){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public void methodB(){
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
SynchronizedTest1 test =new SynchronizedTest1();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test.methodB();
}
});
t2.start();
}
}
/*- 运行结果:
methodA=0
methodB=0
methodA=1
methodB=1
methodA=2
methodB=2
methodB=3
methodA=3
methodA=4
methodB=4
*/
我们可以看出,结果是A,B是在并行运行,synchronized关键字这里没有体现出来
案例二
1.作用在同一个实例对象test1上,synchronized同步方法测试
2.用不同实例对象(test1和test2)调用不同方法
public class SynchronizedTest1_1 {
public synchronized void methodA(){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public synchronized void methodB(){
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
SynchronizedTest1_1 test1 =new SynchronizedTest1_1();
//SynchronizedTest1_1 test2 =new SynchronizedTest1_1();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodB();
//test2.methodB();
}
});
t2.start();
}
}
/*1.实验结果
methodA=0
methodA=1
methodA=2
methodA=3
methodA=4
methodB=0
methodB=1
methodB=2
methodB=3
methodB=4
*/2.略
从实验结果,我们可以看出,两个不同的线程,用同一个对象调用不同的方法,并且两个方法都被synchronized修饰,所以这是给同一个对象加锁.是用同一个对象test1分别调用methodA和methodB,此时给methodA给test1加锁,当线程t2,去调用methodB时,要等待test1从methodA中(解锁)释放,此时是串行,
如果是两个对象调用不同的方法就是并行了.,两个对象互不干扰
案例三
作用在同一个实例对象test1上,
public class SynchronizedTest1_2 {
public synchronized void methodA(){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public synchronized void methodB(){
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
SynchronizedTest1_2 test1 =new SynchronizedTest1_2();
//SynchronizedTest1_2 test2 =new SynchronizedTest1_2();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
//test2.methodA();
}
});
t2.start();
}
}
/*实验结果
methodA=0
methodA=1
methodA=2
methodA=3
methodA=4
methodA=0
methodA=1
methodA=2
methodA=3
methodA=4
*/
从实验结果我们看出,两个线程,但是是同一个对象(test1),调用同一个方法,结果是串行运行,也就是说需要等着test1从上一个线程中释放,下一个才可以使用,但如果是两个不同的对象,就是并行运行,所以这里synchronized锁的是对象(test1).
synchronized同步代码块测试
案例四
作用在同一个实例对象上,
两个线程,一个线程调用synchronized代码块
另一个线程可以调用非synchronized修饰的代码块,
public class SynchronizedTest2 {
public void methodA(){//方法可以异步运行,进来以后内容同步了
//同步代码块 this本类对象
synchronized (this){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public void methodB(){
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
SynchronizedTest2 test1 =new SynchronizedTest2();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodB();
}
});
t2.start();
}
}
/*实验结果
methodA=0
methodB=0
methodB=1
methodA=1
methodB=2
methodA=2
methodA=3
methodB=3
methodB=4
methodA=4
*/
从实验结果可以看出,两个互不干扰,并行运行
案例五
作用在同一个实例对象上, synchronized同步代码块测试
两个线程,一个对象调用,两个synchronized修饰的代码块
public class SynchronizedTest2_1 {
//同步代码块
public void methodA(){
synchronized(this){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
//给代码块加同步
public void methodB(){
synchronized (this){
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SynchronizedTest2_1 test1 =new SynchronizedTest2_1();
//SynchronizedTest2_1 test2 =new SynchronizedTest2_1();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodB();
//test2.methodB();
}
});
t2.start();
}
}
/*实验结果
methodA=0
methodA=1
methodA=2
methodA=3
methodA=4
methodB=0
methodB=1
methodB=2
methodB=3
methodB=4
*/
方法并没有被上锁,但内容代码被上锁了,从实验结果可以看出,当线程1执行,test1调用A时被锁住,当A执行完,释放资源之后,test1才可以被线程2使用调用B,所以此时线程1,2是串行的,
但如果是两个不同的对象调用不同的方法时,就是并行的了
synchronized同步代码块测试和同步方法测试
案例六
作用在作用在同一个实例对象上
1,synchronized和synchronized(this)
public class SynchronizedTest3 {
//给方法加锁
public synchronized void methodA(){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
//给代码块加锁
public void methodB(){
synchronized (this) {
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SynchronizedTest3 test1 =new SynchronizedTest3();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodB();
}
});
t2.start();
}
}
/*实验结果
methodA=0
methodA=1
methodA=2
methodA=3
methodA=4
methodB=0
methodB=1
methodB=2
methodB=3
methodB=4
*/
从实验结果可以看出,synchronized和synchronized(this)二者没有区别,都是作用在this对象上,给this对象加锁,所以会同步,串行运行
案例六
作用在同一个实例对象上, synchronized同步代码块测试和同步方法测试
public class SynchronizedTest3_1 {
//给方法加锁
public synchronized void methodA(){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
//给代码块加锁
public void methodB(){
synchronized (this) {
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public void methodC(){
//可以是new任何对象
Object obj = new Object();
synchronized (obj) {
try{
for(int i=0;i<5;i++){
System.out.println("methodC="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SynchronizedTest3_1 test1 =new SynchronizedTest3_1();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodB();
}
});
t2.start();
Thread t3 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodC();
}
});
t3.start();
}
}
/*实验结果
methodC=1
methodA=2
methodC=2
methodA=3
methodC=3
methodA=4
methodC=4
methodB=0
methodB=1
methodB=2
methodB=3
methodB=4
*/
从实验结果得出synchronized和synchronized(this) 都是作用在this对象上,给this对象加锁而synchronized(obj) 这个是作用在obj对象上,给obj对象添加锁,
所以A和B是串行的,此时C与(A和B)是并行
案例七
作用在同一个实例对象上, synchronized同步代码块测试和同步方法测试
public class SynchronizedTest3_2 {
private Object obj =new Object();
//给方法加锁
public synchronized void methodA(){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
//给代码块加锁
public void methodB(){
synchronized (obj) {
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public void methodC(){
//new任何对象
synchronized (obj){
try{
for(int i=0;i<5;i++){
System.out.println("methodC="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SynchronizedTest3_2 test1 =new SynchronizedTest3_2();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodB();
}
});
t2.start();
Thread t3 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodC();
}
});
t3.start();
}
}
/*实验结果
methodA=0
methodB=0
methodA=1
methodB=1
methodA=2
methodB=2
methodB=3
methodA=3
methodA=4
methodB=4
methodC=0
methodC=1
methodC=2
methodC=3
methodC=4
*/
从实验结果可以看出synchronized修饰的A方法针对的是this对象,而B和C中的synchronized(obj)代码块修饰的是obj对象,所以,methodB和methodC是串行,锁上在obj上,methodA跟(B和C)是并行的
作用在同一个类上,一个类上只有一把锁
案例八
synchronized类锁
static synchronized 和 synchronized(类名.class)
public class SynchronizedTest4 {
//static的修饰的方法属于类
public synchronized static void methodA(){//加静态就锁在类上了
//同步代码块
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public void methodB(){
synchronized (SynchronizedTest4.class){//修饰在类上了
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SynchronizedTest4 test1 =new SynchronizedTest4();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodB();
}
});
t2.start();
}
}
/*
methodA=0
methodA=1
methodA=2
methodA=3
methodA=4
methodB=0
methodB=1
methodB=2
methodB=3
methodB=4
*/
有结果可以看出,static修饰的属于类,所以都是作用在同一个类锁,所以会同步,是串行,
案例九
synchronized的对象锁和static静态的synchronized的类锁
public class SynchronizedTest5 {
public synchronized void methodA(){
try{
for(int i=0;i<5;i++){
System.out.println("methodA="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
public void methodB(){
synchronized (SynchronizedTest5.class){
try{
for(int i=0;i<5;i++){
System.out.println("methodB="+i);
Thread.sleep(1000);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SynchronizedTest5 test1 =new SynchronizedTest5();
Thread t1 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodA();
}
});
t1.start();
Thread t2 =new Thread(new Runnable(){
@Override
public void run() {
test1.methodB();
}
});
t2.start();
}
}
/*实验结果
methodA=0
methodB=0
methodB=1
methodA=1
methodA=2
methodB=2
methodA=3
methodB=3
methodA=4
methodB=4
*/
由结果可以看出,synchronized修饰的属于对象锁而static synchronized的属于类是两个不同的锁,所以是异步的,并行运行
总结:
多个线程,在用同一个对象,调用有synchronized关键字修饰的方法或代码块时,我们要注意,这把锁是给哪个对象,(这个对象属于方法的),被锁住的对象需要在解锁后才可以被其他带锁的方法或代码块使用,此时是串行运行,但是如果其他线程中该对象调用的是其他不带synchronized修饰的方法或代码块时,此时是并发运行的.
synchronized修饰类时有两种形式static synchronized 和 synchronized(类名.class),此时,对象是属于类的,在遇到只有synchronized修饰的方法时,两者对象的归属不同所以是可以并发运行的
String作为锁对象时要慎用