先說一說多線程的實現方式,有兩種,第一種是繼承Thread類,第二種是實現Runnable接口。兩種方法的區別,第一種使用的時候會有多個線程實例所以多個線程訪問的變量不是共享的。
package javabasic;
public class Synchronized extends Thread{
public int a;
@Override
public void run(){
System.out.println(a++);
}
public static void main(String[] args) {
for(int i=0;i<3;i++){
new Synchronized().start();
}
}
}
三個線程訪問的a是不同的;
package javabasic;
public class RunnableInstance implements Runnable{
public int a;
public void run(){
System.out.println(a++);
}
public static void main(String[] args) {
RunnableInstance runnable = new RunnableInstance();
for(int i=0;i<3;i++){
new Thread(runnable).start();
}
}
}
打印結果:
0
2
1
因爲只有一個RunnableInstance實例,所以a是共享的
接下來進入正題
Synchronized有兩種用法:
1.同步代碼塊
package javabasic;
public class Synchronized extends Thread{
public static String str = “aaa”;
@Override
public void run(){
synchronized(str){
System.out.println("開始");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("結束");
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0;i<3;i++){
new Synchronized().start();
}
}
}
synchronized需要鎖住一個對象,這樣多個線程就不能同時執行同步代碼塊的代碼,所以前面我們實現Runnable就可以鎖住實例的一個成員對象,如果繼承Thread則需要鎖住一個靜態對象。
2.同步方法
package javabasic;
public class Synchronized extends Thread{
@Override
public void run(){
sync();
}
public synchronized void sync(){
System.out.println("開始");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("結束");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0;i<3;i++){
new Synchronized().start();
}
}
}
這個程序不能防止多個線程訪問,因爲synchronized方法和下面同步代碼塊的效果一樣
synchronized(this){
//同步代碼
}
因爲繼承Thread,this會指向不同的實例。所以鎖住的不是同一個對象。
那麼使用同步方法時,還是以實現Runnable的方式來同步。
package javabasic;
public class RunnableInstance implements Runnable{
public int a;
public void run(){
sync();
}
public synchronized void sync(){
System.out.println("開始");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("結束");
}
public static void main(String[] args) {
RunnableInstance runnable = new RunnableInstance();
for(int i=0;i<3;i++){
new Thread(runnable).start();
}
}
}