在學習多線程時,如果聯繫操作系統來學習,會覺得很好理解。因爲學習操作系統時候,有同步,互斥,鎖的一些概念~
給個鏈接到上一篇~https://blog.csdn.net/zoweiccc/article/details/83002176
8.加入線程
(1)join,當前線程暫停,等待指定的線程執行結束後,當前線程再繼續
(2)join(int),可以等待指定的毫秒之後繼續,交替繼續
9.禮讓線程
yield讓出cpu
10.設置線程的優先級,最小的優先級是1,最大是10,默認是5
setPriority()
11.什麼情況下需要使用同步
如果多線程併發,有多段代碼同時執行時,我們希望某一段代碼執行的過程中cpu不要切換到其他線程工作,這時就需要同步
如果兩段代碼是同步的,那麼同一時間只能執行一段,在一段代碼沒執行結束之前,不會執行另一段代碼
12.同步代碼塊
使用synchronize關鍵字加上一個鎖對象來定義一段代碼,就叫做同步代碼塊
多個同步代碼塊如果使用相同的鎖對象,那麼他們就是同步的
13.同步方法
使用synchronized關鍵字修飾的一個方法,該方法中所有的代碼都是同步的
非靜態的同步方法的鎖對象是this,靜態的同步方法的鎖對象是該類的字節碼對象,即Pr2.class
14.線程安全問題,用火車站售票例子解釋
15.死鎖:多線程同步時,如果同步代碼嵌套,使用相同鎖,就有可能出現死鎖,爲了避免,不要出現同步代碼塊嵌套
16.一般來說,通過查看類的源碼,如果存在synchronized,則大部分可認爲是線程安全的。
比如:Vector是線程安全的,ArrayList是線程不安全的
StringBuffer是線程安全的,StringBuilder是線程不安全的
Hashtable是線程安全的,HashMap是線程不安全的
package pra_20;
public class J_39 {
/**
* @param args
*/
public static void main(String[] args) {
//8.加入線程
final Thread th1=new Thread(){
public void run(){
for(int i=0;i<10;i++){
System.out.println("1");
}
}
};
Thread th2=new Thread(){
public void run(){
for(int i=0;i<10;i++){
if(i==2){
try {
th1.join(); //匿名內部類在使用所在方法中的局部變量時,必須用final修飾
//th1.join(1)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("2");
}
}
};
th1.start();
th2.start();
//9.禮讓線程
new Mythread2().start();
new Mythread2().start();
//10.設置線程的優先級
Thread th3=new Thread(){
public void run(){
for(int i=1;i<1000;i++){
System.out.println(getName()+"~~~~a");
}
}
};
Thread th4=new Thread(){
public void run(){
for(int i=1;i<1000;i++){
System.out.println(getName()+"~~~~b");
}
}
};
th3.setPriority(10);
th4.setPriority(3);
th3.start();
th4.start();
//12.同步代碼塊
final Pr p1=new Pr();
new Thread(){
public void run(){
while(true){
p1.pri();
}
}
}.start();
new Thread(){
public void run(){
while(true){
p1.pri2();
}
}
}.start();
//13.同步方法
final Pr2 p2=new Pr2();
new Thread(){
public void run(){
while(true){
p2.pri();
}
}
}.start();
new Thread(){
public void run(){
while(true){
p2.pri2();
}
}
}.start();
//14.線程安全問題
new Ticket().start();
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}
class Ticket extends Thread{
private static int ticket=100;
public synchronized void run(){
while(true){
synchronized(Ticket.class){
if(ticket<=0)
break;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("這是第"+ticket--+"張票");
}
}
}
}
//爲了實現同步方法創建的類(非靜態)
class Pr2{
Suo s=new Suo();
//非靜態的同步方法的鎖對象是this,靜態的同步方法的鎖對象是該類的字節碼對象,即Pr2.class
public synchronized void pri(){ //同步方法只需要在方法上加synchronized關鍵字即可
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.println();
}
public void pri2(){
synchronized(this){
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.println();
}
}
}
//爲了實現同步方法創建的類(靜態)
class Pr3{
Suo s=new Suo();
//靜態的同步方法的鎖對象是該類的字節碼對象,即Pr3.class
public static synchronized void pri(){ //同步方法只需要在方法上加synchronized關鍵字即可
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.println();
}
public static void pri2(){
synchronized(Pr3.class){
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.println();
}
}
}
//爲了實現同步代碼塊創建的類
class Pr{
Suo s=new Suo(); //這個鎖對象可以是任意的,隨意創建一個對象即可,下面都表示的同一個鎖
public void pri(){
synchronized (s) { //同步代碼塊,鎖機制,當此方法運行完了才允許同步的執行,但參數不能創建匿名對象,因爲匿名不是同一個
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.println();
}
}
public void pri2(){
synchronized (s) {
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.println();
}
}
}
class Suo{
}
class Mythread2 extends Thread{
public void run(){
for(int i=1;i<1000;i++){
if(i%10==0){
Thread.yield(); //讓出cpu
}
System.out.println(getName()+"~~~~"+i);
}
}
}