您的位置:首页 > 编程语言 > Java开发

【Java】同步 例子

2017-06-24 14:25 197 查看
之前记录了synchronized的基本用法,分为对象和类,以及方法和块。下面是一些结论。

1.方发锁和类锁不是同一个锁。这也是今日头条之前面试过的一个问题。

class Business{

public synchronized void f(){
System.out.println("not static starts");
for(int i = 0; i < 100; i ++){
System.out.println(i);
}
System.out.println("not static ends");
}

public static synchronized void g(){
System.out.println("static starts");
for(int i = 0; i < 100; i ++){
System.out.println(i);
}
System.out.println("static ends");
}
}

public class TThread implements Runnable{

@Override
public void run() {
try{
for(int i = 0; i < 10000; i++){
System.out.println(i);
if(Thread.interrupted()){
throw new InterruptedException();
}
}

}catch(InterruptedException e){
System.out.println("break");
}
}

public static void main(String args[]){
Business b = new Business();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
b.f();
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
b.g();
}
});
t1.start();
t2.start();
}
}
两个线程同时调用了业务类中的一个静态方法和一个非静态方法,都是syn关键字修饰的。那么他们之间不会同步。



这就印证了类锁和对象锁是不同的锁。可以想象为两个锁,因此执行静态方法和非静态方法是无法同步的。互不干扰。因为得到对象锁,不妨碍别的线程得到类锁,得到类锁也不妨碍别的线程得到对象锁。

2.对于对象锁而言,

syn语句块(x){}和x对象调用syn的方法以及x对象调用它的方法中的syn(this){}块之间是同步的。这三种情况。

class Business{

public synchronized void f1(){
System.out.println(Thread.currentThread().getName() + ":f1 starts");
for(int i = 0; i < 3; i ++){
System.out.println(i);
}
System.out.println(Thread.currentThread().getName() + ":f1 ends");
}

public void f2(){
synchronized(this){
System.out.println(Thread.currentThread().getName() + ":f2 starts");
for(int i = 0; i < 3; i ++){
System.out.println(i);
}
System.out.println(Thread.currentThread().getName() + ":f2 ends");
}
}

}

public class TThread implements Runnable{

Business b;

public TThread(Business b){
this.b=b;
}
@Override
public void run() {
f3();
}

public void f3(){
synchronized(b){
System.out.println(Thread.currentThread().getName() + ":f3 starts");
for(int i = 0; i < 3; i ++){
System.out.println(i);
}
System.out.println(Thread.currentThread().getName() + ":f3 ends");
}
}

public static void main(String args[]){
Business b = new Business();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
b.f1();
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
b.f2();
}
});
Thread t3 = new Thread(new TThread(b));
t1.start();
t2.start();
t3.start();
}
}


结果:



3.同步方法,在子类中重写,如果没有指定syn,则不会同步。如果子类没有重写,则会同步。

class Business{

public synchronized void f1(){
System.out.println(Thread.currentThread().getName() + ":f1 starts");
for(int i = 0; i < 30; i ++){
System.out.println(i);
}
System.out.println(Thread.currentThread().getName() + ":f1 ends");
}

}

class Sub extends Business{
@Override
public void f1(){
System.out.println(Thread.currentThread().getName() + ":f1 starts");
for(int i = 0; i < 30; i ++){
System.out.println(i);
}
System.out.println(Thread.currentThread().getName() + ":f1 ends");
}
}

public class TThread implements Runnable{

public static void main(String args[]){
Business b = new Sub();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
b.f1();
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
b.f1();
}
});
t1.start();
t2.start();
}

@Override
public void run() {

}
}
结果:



4.锁对象的改变;

如果把syn块内的对象引用指向别的对象,那么前后的对象锁就不同了,两个线程获取的锁也不同,最后就不会同步了。

class Business{

String lock = "123";
public void f1(){
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ":f1 starts");
lock = "345";
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":f1 ends");
}
}
}

public class TThread implements Runnable{

public static void main(String args[]){
Business b = new Business();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
b.f1();
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
b.f1();
}
});
t1.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}

@Override
public void run() {

}
}
t1先运行,run方法内部把锁对象改变了,这样t2申请的锁是另一个锁,于是可以直接执行。


5.死锁例子:
class Business {

String lock1;
String lock2;

Business(String s1, String s2){
lock1 = s1;
lock2 = s2;
}
public void f1(){
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + ":f1 starts");
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + ":f1 inner starts");
System.out.println(Thread.currentThread().getName() + ":f1 inner ends");
}
System.out.println(Thread.currentThread().getName() + ":f1 ends");
}
}

public void f2() {
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + ":f1 starts");
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + ":f1 inner starts");
System.out.println(Thread.currentThread().getName() + ":f1 inner ends");
}
System.out.println(Thread.currentThread().getName() + ":f1 ends");
}
}
}
public class TThread implements Runnable{

public static void main(String args[]){
Business b = new Business("123", "456");
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
b.f1();
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
b.f2();
}
});
t1.start();
t2.start();
}

@Override
public void run() {

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程