java——多執行緒
1.什麼是程式
狹義:程式是正在執行的程式例項
廣義:程式是一個具有獨立功能的程式關於某個資料集合的一次執行活動,是系統進行資源分配和排程的基本單位
程式的概念要注意兩點:
程式是一個實體。每一個程式都有它自己的獨立地址空間
程式是一個“執行中的程式”。只有當處理器執行這個程式時,它成為活動的實體
2.什麼是執行緒
執行緒是程式中的一個實體,是CPU排程的基本單位,只擁有在執行中必不可少的資源,但它可與同屬一個程式的其他執行緒共享所擁有的資源。
3.執行緒和程式的關係
執行緒是程式的一個實體,一個程式可以擁有多個執行緒。
4.程式和執行緒的區別
(1) 地址空間:同一程式的所有執行緒共享本程式的地址空間,不同程式之間的地址空間是相互獨立的。
(2) 資源擁有:同一程式內的執行緒共享本程式的資源如:記憶體、I/O,CPU等,不同的程式資源相互獨立。
(3) 健壯性:一個程式崩潰後,不會對其他程式產生影響,但是一個執行緒崩潰後,會終結整個程式。所以多程式要比多執行緒健壯。
(4) 執行緒切換比程式切換消耗的資源更少、速度更快。
(5) 執行緒是CPU排程的基本單位,程式是系統資源分配的基本單位。
排程問題
同步與非同步
併發與並行
併發指兩個或多個事件在同一個時間段內發生。
並行指兩個或多個事件在同一時刻發生(同時發生)
開啟兩個執行緒,使用搶佔式的執行方式
他們的執行方式是這樣的
Runnable介面
設定和獲取執行緒名稱
public class setname {
public static void main(String[] args) {
//如何獲取執行緒的名稱
System.out.println(Thread.currentThread().getName());
//兩種設定執行緒名稱的方式
Thread t = new Thread(new MyRunnable());
t.setName("wwww");
t.start();
new Thread(new MyRunnable(),"鋤禾日當午").start();
//不設定的有預設的名字
new Thread(new MyRunnable()).start();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
}
下邊的執行緒不是固定的,執行緒是搶佔執行的
import java.lang.Thread;
public class THread {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
//兩種方式去建立執行緒
MyRunnable mr = new MyRunnable();
Thread t = new Thread(mr);
t.start();
new Thread(new MyRunnable()).start();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
指定時間休眠Sleep
public class setname {
public static void main(String[] args) {
new Thread(new MyRunnable()).start();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("已經休眠完成");
}
}
}
執行緒阻塞就是所有消耗時間的操作。如果用stop直接結束執行緒,那麼它沒辦法及時的把它所擁有的資源去釋放
執行緒的中斷(中斷只是一個標記,告訴執行緒該死亡了,然後線上程中新增死亡的方法)
import sun.management.ThreadInfoCompositeData;
public class setname {
public static void main(String[] args) {
MyRunnable r1=new MyRunnable();
Thread t1=new Thread(r1);
t1.start();
t1.interrupt();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("發現了中斷標記該結束了");
return;
}
System.out.println("已經休眠完成");
}
}
}
在實際程式設計中一般不用stop,stop會強制關閉,如果當時該執行緒沒有釋放所擁有的資源會造成麻煩
守護執行緒
使用者執行緒:當一個程式不包含任何的存活使用者執行緒時,進行結束
守護執行緒: 守護使用者執行緒的,當最後一個使用者執行緒結束時,所有守護執行緒自 動死亡
import sun.management.ThreadInfoCompositeData;
public class setname {
public static void main(String[] args) throws InterruptedException {
MyRunnable r1=new MyRunnable();
Thread t1=new Thread(r1);
//設定t1為守護執行緒,在本例中只有main一個使用者執行緒
t1.setDaemon(true);
t1.start();
for(int i=1;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
Thread.sleep(1000);
}
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("發現了中斷標記該結束了");
return;
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
在本例中,守護執行緒應該執行10次,但是當使用者執行緒main執行完成後,就結束了
執行緒的安全與不安全
public class setname {
public static void main(String[] args) {
//執行緒不安全
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//總票數
private int count = 10;
@Override
public void run() {
while (count>0){
//賣票
System.out.println("正在準備賣票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("賣票結束,餘票:"+count);
}
}
}
}
當餘票剩餘1 的情況下,A進入catch但是此時丟失了時間片,被B拿到,此時count的值還沒來得及改變於是會發生-1張票的情況
執行緒安全的解決方案一——同步程式碼塊(上鎖 ——synchronized,但是上完鎖以後效率就變得不高了,誰先搶到,誰更容易搶到接下來的)
三個執行緒看同一把鎖 Object O
//執行緒同步synchronized
public class setname {
public static void main(String[] args) {
Object o = new Object();
//執行緒不安全
//解決方案1 同步程式碼塊
//格式:synchronized(鎖物件){
//
//
// }
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//總票數
private int count = 10;
private Object o = new Object();
@Override
public void run() {
//Object o = new Object(); //這裡不是同一把鎖,所以鎖不住
while (true) {
synchronized (o) {
if (count > 0) {
//賣票
System.out.println("正在準備賣票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"賣票結束,餘票:" + count);
}else {
break;
}
}
}
}
}
}
可以看到,方法一一旦哪個執行緒搶到了,那麼接下來就會執行很方便
反例,如果Object O放在run裡邊,那麼三個執行緒在建立的時候都看各自的鎖,此時就是執行緒不安全的
方法二 同步方法
//執行緒同步synchronized
public class setname {
public static void main(String[] args) {
Object o = new Object();
//執行緒不安全
//解決方案2 同步方法
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//總票數
private int count = 10;
@Override
public void run() {
while (true) {
boolean flag = sale();
if(!flag){
break;
}
}
}
public synchronized boolean sale(){
if (count > 0) {
//賣票
System.out.println("正在準備賣票");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"賣票結束,餘票:" + count);
return true;
}
return false;
}
}
}
需要注意的是這裡
如果裡邊new 三個Ticket
排隊的物件是裡邊建立的這個Ticket,現在裡邊新建立的,三個,會呼叫三個run,沒有實現排隊機制,而之前裡邊放的是run,三個執行緒使用他會被鎖,實現排隊機制,但是上面這種方式不行
方法三——顯示鎖
一定注意鎖的引數,如果是false,那麼很大可能被某一個執行緒獨佔資源,其他執行緒得不到資源的分配
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//同步程式碼塊和同步方法都屬於隱式鎖
//執行緒同步lock
public class setname {
public static void main(String[] args) {
//執行緒不安全
//解決方案1 顯示鎖 Lock 子類 ReentrantLock
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//總票數
private int count = 10;
//引數為true表示公平鎖 預設是false 不是公平鎖
private Lock l = new ReentrantLock(true);
@Override
public void run() {
while (true) {
l.lock();
if (count > 0) {
//賣票
System.out.println("正在準備賣票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"賣票結束,餘票:" + count);
}else {
break;
}
l.unlock();
}
}
}
}
公平鎖:誰先到誰得到鎖
非公平鎖:大家一塊搶
上邊是喚醒所有執行緒,下邊是讓當前執行緒睡著。
多執行緒通訊——生產者消費者問題,就像是廚師和服務員一樣,當廚師在工作的時候,服務員執行緒在wait(沉睡),當服務員送餐的時候廚師在(wait)
public class setname {
public static void main(String[] args) {
//多執行緒通訊 生產者與消費者問題
Food f = new Food();
new Cook(f).start();
new Waiter(f).start();
}
//廚師
static class Cook extends Thread{
private Food f;
public Cook(Food f) {
this.f = f;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i%2==0){
f.setNameAndTaste("老乾媽小米粥","香辣味");
}else {
f.setNameAndTaste("煎餅果子","甜辣味");
}
}
}
}
//服務員
static class Waiter extends Thread{
private Food f;
public Waiter(Food f) {
this.f = f;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
f.get();
}
}
}
//食物
static class Food{
private String name;
private String taste;
//true表示可以生產
boolean flag = true;
public synchronized void setNameAndTaste(String name,String taste){
if(flag){
this.name = name;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.taste = taste;
flag = false;
this.notifyAll();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void get(){
if(!flag){
System.out.println("服務員端走的菜的名稱是:"+name+",味道是:"+taste);
flag = true;
this.notifyAll();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
執行緒的狀態
執行緒的狀態轉換
Java中第三種執行緒Callable實現方式(作為了解)
返回值會先列印下邊的123456789,然後get方法等待子執行緒執行完成後再執行他自己的執行緒
判斷執行緒是否執行完
取消執行緒
執行緒池是容納多個執行緒的容器(相當於一個執行緒陣列)開發中很少使用執行緒池。(java中有四種執行緒池)
快取執行緒池
向執行緒池中加入任務(指揮執行緒池執行新的任務)
再複製那個方法,因為執行緒池中已經有了快取,所以會呼叫在快取中的
定長執行緒池
單執行緒執行緒池
執行完不會關閉還在等待傳入,但是在一定時間後還會自動關閉的
週期執行緒池
Lambda表示式
以前建立執行緒的方式
匿名內部類的使用(比原來簡便一些)
函數語言程式設計
介面只有一個方法才可以使用lambda表示式
修改後的
相關文章
- Java多執行緒-執行緒中止Java執行緒
- 【Java多執行緒】輕鬆搞定Java多執行緒(二)Java執行緒
- java多執行緒Java執行緒
- Java - 多執行緒Java執行緒
- java 多執行緒Java執行緒
- Java多執行緒之執行緒中止Java執行緒
- Java多執行緒-執行緒狀態Java執行緒
- Java多執行緒-執行緒通訊Java執行緒
- java 多執行緒守護執行緒Java執行緒
- Java多執行緒(2)執行緒鎖Java執行緒
- java多執行緒9:執行緒池Java執行緒
- 【java多執行緒】(二)執行緒停止Java執行緒
- Java多執行緒學習(一)Java多執行緒入門Java執行緒
- Java多執行緒(一)多執行緒入門篇Java執行緒
- 【Java多執行緒】執行緒安全的集合Java執行緒
- 【Java】【多執行緒】執行緒池簡述Java執行緒
- Java多執行緒-執行緒池的使用Java執行緒
- java 多執行緒CountDownLatchJava執行緒CountDownLatch
- java 多執行緒-3Java執行緒
- java 多執行緒-2Java執行緒
- java 多執行緒 –同步Java執行緒
- java使用多執行緒Java執行緒
- Java--多執行緒Java執行緒
- java 多執行緒 --同步Java執行緒
- java多執行緒原理Java執行緒
- Java多執行緒學習——執行緒通訊Java執行緒
- Java多執行緒學習(2)執行緒控制Java執行緒
- Java 多執行緒基礎(四)執行緒安全Java執行緒
- java多執行緒之執行緒的基本使用Java執行緒
- 【Java】【多執行緒】執行緒的生命週期Java執行緒
- Java多執行緒詳解——一篇文章搞懂Java多執行緒Java執行緒
- Java多執行緒之守護執行緒實戰Java執行緒
- 深入淺出Java多執行緒(十二):執行緒池Java執行緒
- Java 多執行緒基礎(八)執行緒讓步Java執行緒
- java多執行緒:執行緒池原理、阻塞佇列Java執行緒佇列
- java多執行緒5:執行緒間的通訊Java執行緒
- Java多執行緒之執行緒同步【synchronized、Lock、volatitle】Java執行緒synchronized
- Java中的多執行緒Java執行緒