一. 線程之間的通信
1.1wait()等待將當前線程從運行狀態便到阻塞狀態(釋放對象鎖)
1.2 noytify()
只喚醒一個對應對象所的一個線程
1.3 notifyAll()
喚醒全部對應對象所的線程
public class Demo01 {
public static void main(String[] args) {
/*線程之間的通信:多線程之間的
* wait()等待 將當前線程從運行狀態便到阻塞狀態(釋放對象鎖)
* noytify() 只喚醒一個對應對象所的一個線程
* notifyAll() 喚醒全部對應對象所的線程
*
* 上面三個方法:是屬於Object類的,不是線程特有的方法
*
*上訴方法要在同步代碼裏面使用纔有意義
*/
MyThread13 th=new MyThread13();
try {
th.notify();
} catch (Exception e) {
// TODO: handle exception
}
}
}
class MyThread13 extends Thread{
}
二.線程安全問題
public class LockDemo02 {
public static void main(String[] args) {
/*線程安全問題:僅限於多線程
* 鎖對象的概念:
* 在JAVA中每一個對象都有一個內置的對象鎖,並且整個鎖只有一把鑰匙。
* 這就決定了當一個線程獲取了該對象鎖的時候別的線程無法再去獲取,只有當獲取對象鎖的線程釋放了鎖以後才能去使用。
*
* 常用兩種鎖對象的方式:
* 一種是對象,
* 一種是class文件 (類.class 或者對象.getClass())
*
* 1.同步代碼塊 本質鎖對象
* 2.同步方法 (普通的方法 以及靜態方法)
* 同步普通方法鎖的也是對象
* 同步靜態方法鎖的是 字節碼文件 (.class)
*
*/
Mythread11 th=new Mythread11();
Thread th1=new Thread(th,"窗口1");
Thread th2=new Thread(th,"窗口2");
Thread th3=new Thread(th,"窗口3");
th1.start();
th2.start();
th3.start();
}
}
class Mythread11 implements Runnable{
private int ticket=50;
@Override
public void run() {
// while(true){
// synchronized (Mythread11.class) {//同步代碼塊
// if(ticket>0){
// try {
// Thread.sleep(200);
// } catch (Exception e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName()+"D360還剩"+ticket+"張票");
// ticket--;
// }
// else{
// System.out.println("很遺憾,沒票了");
// break;
// }
// }
//
// }
method(); //調用同步方法
}
//同步方法 同步可以定義在 自定義的類當中,不限於線程類
public synchronized void method(){
while(true){
synchronized (Mythread11.class) {//同步代碼塊
if(ticket>0){
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"D360還剩"+ticket+"張票");
ticket--;
}
else{
System.out.println("很遺憾,沒票了");
break;
}
}
}
}
}
2.1僅限於多線程
2.2 鎖對象的概念在JAVA中每一個對象都有一個內置的對象鎖,並且整個鎖只有一把鑰匙。
* 這就決定了當一個線程獲取了該對象鎖的時候別的線程無法再去獲取,只有當獲取對象鎖的線程釋放了鎖以後才能去使用。
一種是對象
常用兩種鎖對象的方式:
一種是class文件 (類.class 或者對象.getClass())
2.3 線程退讓
public class YieldDemo {
public static void main(String[] args) {
/*線程退讓
* 線程的優先級:默認優先級爲5
* 注意:線程在執行過程中不能改變優先級,必須在線程開啓之前設置優先級
* 範圍:1-10數字越大優先級越大
*/
MyThread10 th=new MyThread10();
th.setName("線程一");
th.setPriority(Thread.MAX_PRIORITY); //最大優先級
System.out.println(th.getPriority());
MyThread10 th1=new MyThread10();
th1.setName("線程二");
th1.setPriority(Thread.MIN_PRIORITY);
th.start();
th1.start();
}
}
class MyThread10 extends Thread{
int i=1;
@Override
public void run() {
while(i<100){
if(i==50){
Thread.yield(); //線程讓步
}
System.out.println(Thread.currentThread().getName()+"=="+i);
i++;
}
}
}
線程的優先級
默認優先級爲5注意:線程在執行過程中不能改變優先級,必須在線程開啓之前設置優先級
範圍:1-10數字越大優先級越大
三.生產者和消費者模式
3.1 Clerk
//商店類
public class Clerk {
/*
* 主要負責兩個內容:
* 1.有貨通知消費者去買東西
* 1.1
* 2.沒貨的時候通知生產者生產東西
* 2.1
*
*
* wait:在當前運行線程調用的時候回主動釋放掉對象鎖並進入到阻塞的狀態,如果該線程想恢復到就緒狀態,則必須等到同一個對象
* 調用notify/notifyAll()方法才行
*
* 概念:線程池
*/
private int goodsNum=20; //默認商店目前有最大持有商品數
//生產者的
public synchronized void add(){
if(goodsNum>=20){//貨滿的時候
System.out.println("sorry,商店期貨過多,請稍停生產");
try {
this.wait();//讓生產者等地
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
++goodsNum;
System.out.println("生產了第"+goodsNum+"個商品給"+Thread.currentThread().getName());
this.notify();//喚醒通知生產者可以生產商品
}
}
//消費者
public synchronized void sell(){
if(goodsNum<=0){
System.out.println("sorry,商店沒貨 了");
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
System.out.println("賣了第"+goodsNum+"個商品給"+Thread.currentThread().getName());
goodsNum--;
this.notify();
}
}
3.2 Consumer
public class Consumer implements Runnable {
private Clerk clerk;
public Consumer(Clerk clerk) {
super();
this.clerk = clerk;
}
@Override
public void run() {
while(true){
try {
Thread.sleep((int)(Math.random()*1000));
} catch (Exception e) {
// TODO: handle exception
}
clerk.sell();
}
}
}
3.3 Productor
//生產者一個線程類
public class Productor implements Runnable{
private Clerk clerk;
public Productor(Clerk clerk) {
super();
this.clerk = clerk;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clerk.add();//
}
}
}
3.4 TestDemo
public class TestDemo {
public static void main(String[] args) {
/*
*
*測試類
*
*/
Clerk clerk=new Clerk();
Productor pro =new Productor(clerk);
Consumer con=new Consumer(clerk);
Thread th1=new Thread(pro,"生產者一");
Thread th2=new Thread(con,"消費者一");
th1.start();
th2.start();
}
}
四. 死鎖和同步靜態方法鎖
4.1 死鎖當一個線程擁有另一個線程的資源所得時候,而另一個也擁有該線程的資源所。
* 彼此都必須在獲得對方資源鎖的時候才能持續運行。
* 當兩方都不退讓的時候,就會陷入一種僵持狀態----死鎖
public class DeadLockDemo {
public static void main(String[] args) {
/*死鎖:當一個線程擁有另一個線程的資源所得時候,而另一個也擁有該線程的資源所。
* 彼此都必須在獲得對方資源鎖的時候才能持續運行。
* 當兩方都不退讓的時候,就會陷入一種僵持狀態----死鎖
*
* 產生的前提是:
* 線程之間持有相同的對象鎖,獲取對象鎖的順序反過來。。
*/
Battery battery =new Battery("南孚");
Controler controler=new Controler("遙控器");
//
new Thread(new Runnable() {
@Override
public void run() {
synchronized (controler) { //有遙控器沒電池
System.out.println("小妹啊,我手裏拿着遙控器,你不給電池我我就不給遙控器你");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//在等待電池
synchronized (battery) {
System.out.println("哈哈哈哈,終於可以看喜洋洋了");
}
}
}
},"小明").start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (battery) {
System.out.println("哥哥,我手裏拿着電池,你不給遙控器我就不給電池你,哼。。。");
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
synchronized (controler) {
System.out.println("還是哥哥好,終於給遙控器我了,哈哈哈哈。。");
}
}
}
} ,"小紅").start();
}
}
//電池類
class Battery{
public String name;
public Battery(String name) {
super();
this.name = name;
}
}
//遙控器類
class Controler{
public String name;
public Controler(String name) {
super();
this.name = name;
}
}
4.1.1 產生的前提是:
* 線程之間持有相同的對象鎖,獲取對象鎖的順序反過來。
同步靜態方法鎖的是什麼?
* 鎖的是字節碼文件,不是對象
public class StaticDemo {
public static void main(String[] args) {
/*同步靜態方法鎖的是什麼?
* 鎖的是字節碼文件,不是對象
*
*
*
*/
Test test1=new Test();
Test test2=new Test();
MyThread12 th1=new MyThread12(test1);
MyThread12 th2=new MyThread12(test2);
th1.setName("線程一");
th2.setName("線程二");
th1.start();
th2.start();
}
}
class Test{
//同步靜態方法
public synchronized static void fun(){
System.out.println(Thread.currentThread().getName()+"進入fun()方法");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"離開fun()方法");
}
public void fun2(){
fun(); //調用同步靜態方法
}
}
class MyThread12 extends Thread{
private Test test;
public MyThread12(Test test) {
super();
this.test = test;
}
@Override
public void run() {
test.fun2(); //
}
}