摘要:JAVA thread
並行性
產生Thread的方法
方法一: 繼承Thread類
1. 子類覆寫父類中的run方法,將執行緒運行動作放在run函數中。
2. 建立子類物件的同時,執行緒也被創建
3. 使用start方法啟動執行緒
class Demo extends Thread{
public void run(){
for(int x = 0; x < 60; x++){
System.out.println("Demo Run " + x);
}
}
}
class Test{
public static void main(String args[]){
Demo mDemo = new Demo();
mDemo.start();
for(int x = 0; x < 60; x++){
System.out.println("Main Function " + x);
}
}
}
方法二: 實作Runnable介面
1. 子類覆寫介面中的run方法
2. 通過Thread類創建執行緒,並將實現了 Runnable介面的子類物件作為參數傳遞給 Thread類的構造函數
3. Thread類物件調用start方法開啟執行緒。
思考:為什麼要給Thread類的構造函數傳遞 Runnable的子類物件?
安全問題:
多執行緒下共享資源時,需注意互斥問題。利用同步來解決
問題:
class Hello{
public static void main(String[] args){
Resource r = new Resource();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
class Resource{
String name;
int sex;
}
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x == 0){
r.name = "A";
r.sex = 0;
}else{
r.name = "B";
r.sex = 1;
}
x = (x + 1)%2;
}
}
}
class Output implements Runnable{
Resource r = new Resource();
Output(Resource r){
this.r = r;
}
public void run(){
while(true){
System.out.println(r.name + "..." + r.sex);
//B...0, B...1, A...0, A...1 問題發生
}
}
}
解決 加入同步
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
synchronized(r){
if(x == 0){
r.name = "A";
r.sex = 0;
}else{
r.name = "B";
r.sex = 1;
}
x = (x + 1)%2;
}
}
}
}
class Output implements Runnable{
Resource r;
Output(Resource r){
this.r = r;
}
public void run(){
while(true){
synchronized (r) {
System.out.println(r.name + "..." + r.sex);
}
}
}
}
synchronized(物件)
{
需要同步的程式片段;
}
同步需要兩個或者兩個以上的執行緒,多個執行緒使用的是同一個鎖,未滿足這兩個條件,不能稱其為同步。
同步函數
public synchronized void Test(){
}
同步函數被static修飾後其共用的鎖就不是this,因為static不可用this
可使用該類別物件,即類別名稱 .class 當鎖
喚醒等待機制
class Resource{
String name;
int sex;
boolean flag = false;
}
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
synchronized(r){
if(r.flag)
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(x == 0){
r.name = "A";
r.sex = 0;
}else{
r.name = "B";
r.sex = 1;
}
x = (x + 1)%2;
r.flag = true;
r.notify();
}
}
}
}
class Output implements Runnable{
Resource r;
Output(Resource r){
this.r = r;
}
public void run(){
while(true){
synchronized (r) {
if(!r.flag){
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(r.name + "..." + r.sex);
r.flag = false;
r.notify();
}
}
}
}
wait(), notity(), notifyAll()
都使用在同步中,因為要對持有監視器的執行緒操作,所以要使用在同步中,因為只有同步才具有鎖
修改
class Hello{
public static void main(String[] args){
Resource r = new Resource();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}
class Resource{
private String name;
private int sex;
private boolean flag = false;
public synchronized void set(String name, int sex){
if(flag){
try{this.wait();}catch(Exception e){}
}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out(){
if(!flag){
try{this.wait();}catch(Exception e){}
}
System.out.println(name + "..." + sex);
flag = false;
this.notify();
}
}
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x == 0){
r.set("A", 0);
}else{
r.set("B", 1);
}
x = (x + 1)%2;
}
}
}
class Output implements Runnable{
Resource r;
Output(Resource r){
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
修正 多生產者及多消費者時,產生的非同步錯誤,使用notifyAll()
while判斷可以讓被喚醒的thread再一次判斷標記,使用notify()容易出現只喚醒本方thread,導致程序中的所以thread都變成等待,因為本方會因flag而卡住,故使用notifyAll()
class Hello{
public static void main(String[] args){
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name){
while(flag){
try{this.wait();}catch(Exception e){}
}
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName() + "---生產者---" + this.name);
flag = true;
this.notifyAll();
}
public synchronized void out(){
while(!flag){
try{this.wait();}catch(Exception e){}
}
System.out.println(Thread.currentThread().getName() + "消費者" + this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable{
private Resource res;
Producer(Resource res){
this.res = res;
}
public void run(){
int x = 0;
while(true){
res.set("+A+");
}
}
}
class Consumer implements Runnable{
Resource res;
Consumer(Resource res){
this.res = res;
}
public void run(){
while(true){
res.out();
}
}
}
2. 使用interrupt中斷方法。該方法是結束執行緒的凍結狀態,使執行緒回到運行狀態
setPriority(int num)
setDaemon(boolean b)
join()
自訂執行緒名稱
toString()
Lock介面
Lock 實作提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作
使用Lock修改
class Hello{
public static void main(String[] args){
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource{
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void set(String name) throws InterruptedException{
lock.lock();
try{
while(flag){
condition.await();
}
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName() + "---生產者---" + this.name);
flag = true;
condition.signalAll();
}finally{
lock.unlock();//一定要關閉資源
}
}
public void out() throws InterruptedException{
lock.lock();
try{
while(!flag){
condition.await();
}
System.out.println(Thread.currentThread().getName() + "消費者" + this.name);
flag = false;
condition.signalAll();
}finally{
lock.unlock();
}
}
}
class Producer implements Runnable{
private Resource res;
Producer(Resource res){
this.res = res;
}
public void run(){
int x = 0;
while(true){
try {
res.set("+A+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
Resource res;
Consumer(Resource res){
this.res = res;
}
public void run(){
while(true){
try {
res.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
控制Thread
當沒有指定的方式讓凍結的tread恢復到運行狀態,這時需要對凍結進行清除
強制讓tread恢復到運行狀態中來,這樣就可以讓thread結束
利用Thread類別提供的interrupt();方法
//stop方法已經過時
//停止thread要使用run方法結束
//需控制循環結構讓run方法結束
class Hello{
public static void main(String[] args){
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 0;
while(true){
if(num++ == 60){
//st.changeFlag();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName() + ".....num");
}
System.out.println("over");
}
}
class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try{
wait();//wait後 其他thread就可以進入此 synchronized 方法
}catch(InterruptedException e){
System.out.println(Thread.currentThread().getName() + ".....Excetpion");
flag =false;
}
System.out.println(Thread.currentThread().getName() + ".....run");
}
}
public void changeFlag(){
flag = false;
}
}
setDaemon()當主執行緒結束後,也會讓呼叫此方法的執行緒結束
將該執行緒標記為守護執行緒或使用者執行緒
class Hello{
public static void main(String[] args){
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();
int num = 0;
while(true){
if(num++ == 60){
//st.changeFlag();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName() + ".....num");
}
System.out.println("over");
}
}
class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try{
wait();
}catch(InterruptedException e){
System.out.println(Thread.currentThread().getName() + ".....Excetpion");
flag =false;
}
System.out.println(Thread.currentThread().getName() + ".....run");
}
}
public void changeFlag(){
flag = false;
}
}
join()
當a執行緒執行到了b執行緒的join()方法時,a就會等待,等b執行緒執行完,a才會執行
class Hello{
public static void main(String[] args) throws InterruptedException{
Demo st = new Demo();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t1.join();//t1向cpu搶奪執行權 做完才給主執行緒
t2.start();
for(int x = 0; x <5; x++){
System.out.println("main ..." + x);
}
System.out.println("over");
}
}
class Demo implements Runnable{
public void run(){
for(int x = 0; x <5; x++){
System.out.println(Thread.currentThread().getName() + "..." + x);
}
}
}
執行結果:
-----------------------------------------
Thread-0...0
Thread-0...1
Thread-0...2
Thread-0...3
Thread-0...4
main ...0
main ...1
main ...2
main ...3
main ...4
over
Thread-1...0
Thread-1...1
Thread-1...2
Thread-1...3
-----------------------------------------
//setPriority();、toString();
class Hello{
public static void main(String[] args) throws InterruptedException{
Demo st = new Demo();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t1.setPriority(Thread.MAX_PRIORITY);//10
t2.start();
for(int x = 0; x <80; x++){
System.out.println("main ..." + x);
}
System.out.println("over");
}
}
class Demo implements Runnable{
public void run(){
for(int x = 0; x <70; x++){
System.out.println(Thread.currentThread().toString() + "..." + x);.
}
}
}
//yeild();
class Hello{
public static void main(String[] args) throws InterruptedException{
Demo st = new Demo();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
for(int x = 0; x <80; x++){
System.out.println("main ..." + x);
}
System.out.println("over");
}
}
class Demo implements Runnable{
public void run(){
for(int x = 0; x <70; x++){
System.out.println(Thread.currentThread().toString() + "..." + x);
Thread.yield();//暫停當前正在執行的執行緒物件,並執行其他執行緒。
}
}
}
使用封裝方法產生執行緒去執行特定方法,提高並行性
class Hello{
public static void main(String[] args) throws InterruptedException{
new Thread(){
public void run(){
for(int x = 0; x < 100; x++){
System.out.println(Thread.currentThread().getName() + "..." + x);
}
}
}.start();
for(int x = 0; x < 100; x++){
System.out.println(Thread.currentThread().getName() + "..." + x);
}
Runnable r = new Runnable(){
public void run(){
for(int x = 0; x < 100; x++){
System.out.println(Thread.currentThread().getName() + "..." + x);
}
}
};
new Thread(r).start();
}
}