Day25-C:\Users\Lenovo\Desktop\note\code\JavaSE\Basic\src\com\Threadcase-多線程講到等待喚醒機(jī)制的一半
多線程
進(jìn)程
進(jìn)程是程序的基本執(zhí)行實(shí)體
線程
線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,它被包含在進(jìn)程中,是進(jìn)程中實(shí)際運(yùn)行的基本單位
應(yīng)用軟件中相互獨(dú)立,可以獨(dú)立運(yùn)行的功能
多線程就是同時(shí)運(yùn)行多個(gè)子程序,提高效率
并發(fā)
在同一時(shí)刻,有多個(gè)指令在單個(gè)CPU上交替運(yùn)行
并行
在同一時(shí)刻,有多個(gè)指令在多個(gè)CPU上同時(shí)運(yùn)行
package Basic.src.com.Threadcase.Threadcase1;
public class MyThread extends Thread{
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"Hello,World");
}
}
}
package Basic.src.com.Threadcase.Threadcase1;
public class ThreadDemo {
/*
* 多線程的第一種啟動方式:
* 1.定義一個(gè)類其繼承thread類
* 2.重寫里面的run方法
* 3.創(chuàng)建子類的對象,并啟動線程
*
* */
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
//start()才表示開啟線程
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
package Basic.src.com.Threadcase.Threadcase2;
public class MyRun implements Runnable{
private String name;
@Override
public void run() {
//書寫線程需要的代碼
for (int i = 0; i <100; i++) {
Thread t = Thread.currentThread();//getName方法得在Thread類里面找
System.out.println(t.getName()+"Hello World");
System.out.println(Thread.currentThread().getName()+"Hello World!");
}
}
}
package Basic.src.com.Threadcase.Threadcase2;
public class ThreadDemo {
/*
* 多線程的第二種啟動方式:
* 1.自己定義一個(gè)類實(shí)現(xiàn)Runnable接口
* 2.重寫里面的run方法
* 3.創(chuàng)建自己的類的對象
* 4.創(chuàng)建一個(gè)Thread類對象并開啟線程
*
*
* */
public static void main(String[] args) {
//創(chuàng)建MyRun對象
//表示多線程要執(zhí)行的任務(wù)
MyRun mr = new MyRun();
//創(chuàng)建線程對象
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
//線程設(shè)置名字
t1.setName("Thread1");
t2.setName("Thread2");
//開啟線程
t1.start();
t2.start();
}
}
package Basic.src.com.Threadcase.Threadcase3;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {//Integer是返回的結(jié)構(gòu)的類型
@Override
public Integer call() throws Exception {
//求1~100之間的和
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
}
package Basic.src.com.Threadcase.Threadcase3;
import Basic.src.com.Threadcase.Threadcase1.MyThread;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo {
/*
* 多線程的第三種啟動方式:
* 特點(diǎn):可以獲取到多線程運(yùn)行的結(jié)構(gòu)
* 1.自己定義一個(gè)MyCallable類實(shí)現(xiàn)Callable接口
* 2.重寫里面的call方法,有返回值
* 3.創(chuàng)建自己的MyCallable類的對象
* 4.創(chuàng)建一個(gè)FutureTask類對象作用管理多線程運(yùn)行的結(jié)果
*5.創(chuàng)建Thread類的對象,并啟動(表示線程)
*
* */
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3.創(chuàng)建自己的MyCallable類的對象,表示多線程要執(zhí)行的任務(wù)
MyCallable mc = new MyCallable();
//4.創(chuàng)建一個(gè)FutureTask類對象作用管理多線程運(yùn)行的結(jié)果
FutureTask<Integer> ft = new FutureTask<>(mc);
//5.創(chuàng)建Thread類的對象,并啟動(表示線程)
Thread t1 = new Thread(ft);//public Thread(Runnable target)
//啟動線程
t1.start();
//獲取多線程
Integer res = ft.get();
System.out.println(res);
}
}
搶占式調(diào)度(與非搶占式調(diào)度區(qū)別)
搶占式調(diào)度:隨機(jī)
具有優(yōu)先級
package Basic.src.com.Threadcase.ThreadPriority;
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
Thread t = Thread.currentThread();
System.out.println(t.getName()+"---------"+i);
}
}
}
package Basic.src.com.Threadcase.ThreadPriority;
public class ThreadDemo {
public static void main(String[] args) {
//創(chuàng)建線程所要執(zhí)行的參數(shù)對象
MyRunnable mr = new MyRunnable();
//創(chuàng)建線程對象
Thread t1 = new Thread(mr,"飛機(jī)");
Thread t2 = new Thread(mr,"坦克");
System.out.println(t1.getPriority());//默認(rèn)優(yōu)先級是5
System.out.println(t2.getPriority());
System.out.println(Thread.currentThread().getPriority());//5
//優(yōu)先級越高搶到cpu的概率就越高
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}
}
守護(hù)線程
package Basic.src.com.Threadcase.DaemonThread;
public class MyThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i <= 10; i++) {
System.out.println(getName()+"@"+i);
}
}
}
package Basic.src.com.Threadcase.DaemonThread;
public class MyThread2 extends Thread {
public void run() {
for (int i = 0; i <= 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
package Basic.src.com.Threadcase.DaemonThread;
import Basic.src.com.Threadcase.Threadcase1.MyThread;
public class ThreadDemo {
public static void main(String[] args) {
/*
* 當(dāng)其他非守護(hù)線程執(zhí)行結(jié)束后,守護(hù)線程也會陸續(xù)結(jié)束
* 當(dāng)女神線程結(jié)束了,備胎也沒有存在的必要
* */
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.setName("女神");
t2.setName("備胎");
//把第二個(gè)線程設(shè)置為守護(hù)線程(備胎線程)
t2.setDaemon(true);
t1.start();
t2.start();
}
}
出讓線程
package Basic.src.com.Threadcase.Threadyield;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
//表示出讓當(dāng)前CPU的執(zhí)行權(quán)
Thread.yield();//提高均勻度(一定程度上)
}
}
}
package Basic.src.com.Threadcase.Threadyield;
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("飛機(jī)");
t2.setName("坦克");
t1.start();
t2.start();
}
}
插入線程
package Basic.src.com.Threadcase.ThreadJoin;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
package Basic.src.com.Threadcase.ThreadJoin;
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
/*
*
* */
MyThread t = new MyThread();
t.setName("土豆");
t.start();
//把t線程插入到當(dāng)前線程之前:當(dāng)前main線程
t.join();
//執(zhí)行在main線程中
for (int i = 0; i <= 10; i++) {
System.out.println("main"+i);
}
}
}
代碼的生命周期
線程安全
同步代碼塊
package Basic.src.com.Threadcase.ThreadTicket;
public class MyThread extends Thread{
static int ticket = 0;//static表示這個(gè)類所有的對象共享ticket,不加會賣票300張
@Override
public void run() {
while (true) {
//同步代碼塊
synchronized (MyThread.class) {//鎖對象一定要是唯一的
if (ticket < 100) {
try {
Thread.sleep(100);//睡眠時(shí)沒有CPU執(zhí)行權(quán),會被其他線程搶走
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket++;
System.out.println(getName()+"正在賣票第"+ ticket+"張票!!");
}else{
break;
}
}
}
}
}
package Basic.src.com.Threadcase.ThreadTicket;
public class ThreadDemo {
public static void main(String[] args) {
/*
* 需求:某電影院正在上映國產(chǎn)大片,一共有100張票,而他有三個(gè)窗口賣,請?jiān)O(shè)計(jì)一個(gè)程序模擬電影院賣票
* */
//創(chuàng)建線程對象
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
//起名字
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
//開啟線程
t1.start();
t2.start();
t3.start();
}
}
同步方法
package Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1;
public class MyRunnable implements Runnable {
int ticket = 0;
@Override
public void run() {
//1.循環(huán)
//2.同步代碼塊(同步方法)
//3.判斷共享數(shù)據(jù)是否到了末尾,如果到了末尾
//4.判斷共享數(shù)據(jù)是否到了末尾,如果沒有到末尾
while (true) {
if (method()) break;
}
}
//ctrl+alt+M
//this默認(rèn)(非靜態(tài)),此時(shí)是唯一的,因?yàn)镸yRunnable只實(shí)現(xiàn)了一次
private synchronized boolean method() {
//達(dá)到末尾
if (ticket == 100) {
return true;
}
//沒有達(dá)到末尾
else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket++;
System.out.println(Thread.currentThread().getName()+"在賣第"+ticket+"張票");
}
return false;
}
}
package Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1;
public class ThreadDemo {
/*
* 需求:某電影院正在上映國產(chǎn)大片,一共有100張票,而他有三個(gè)窗口賣,請?jiān)O(shè)計(jì)一個(gè)程序模擬電影院賣票
* 利用同步方法完成
* 技巧:同步代碼塊
* */
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
Thread t3 = new Thread(mr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
StringBuilder和StringBuffer
StringBuilder非線程安全
StringBuffer線程安全
Lock鎖
是接口不能直接實(shí)例化,可以采用它的實(shí)現(xiàn)類ReentrantLock來實(shí)例化
package Basic.src.com.Threadcase.ThreadSafe.Lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyThread extends Thread {
static int ticket = 0;
static Lock lock = new ReentrantLock();//Lock是接口不能直接實(shí)例化
//必須加上static關(guān)鍵字在lock前面,否則就是三個(gè)對象三把鎖
//如果鎖對象不聲明為 static,則它是實(shí)例成員變量—— 每個(gè)類的實(shí)例會擁有獨(dú)立的鎖對象。
// 此時(shí),不同實(shí)例的線程會持有不同的鎖,無法實(shí)現(xiàn)跨實(shí)例的同步,導(dǎo)致同步失效。
@Override
public void run() {
while (true) {
//同步代碼塊,不能寫在循環(huán)外面,否則會一直是一個(gè)窗口搶票
//synchronized (Basic.src.com.Threadcase.ThreadSafe.Lock.MyThread.class) {//鎖對象一定要是唯一的。MyThread.class表示當(dāng)前類的字節(jié)碼文件對象
lock.lock();//上鎖與synchronized重復(fù)
try {
if (ticket == 100) {
break;//break會跳過unlock,
}
//沒有達(dá)到末尾
else {
Thread.sleep(100);
ticket++;
System.out.println(Thread.currentThread().getName()+"在賣第"+ticket+"張票");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {//finally里面保證了鎖一定被釋放
lock.unlock();//開鎖
}
//}
}
}
}
package Basic.src.com.Threadcase.ThreadSafe.Lock;
import Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1.MyRunnable;
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
死鎖
是一個(gè)錯(cuò)誤
指的是鎖的嵌套
package Basic.src.com.Threadcase.ThreadSafe.DeadLock;
public class MyThread extends Thread{
static Object objA = new Object();
static Object objB = new Object();
@Override
public void run() {
while(true){
if("線程A".equals(Thread.currentThread().getName())){
synchronized (objA){
System.out.println("線程A拿到了A鎖,準(zhǔn)備拿B鎖");
synchronized (objB){
System.out.println("線程A拿到了B鎖,順利執(zhí)行完一輪");
}
}
} else if ("線程B".equals(Thread.currentThread().getName())) {
synchronized (objB){
System.out.println("線程B拿到了B鎖,準(zhǔn)備拿A鎖");
synchronized (objA){
System.out.println("線程B拿到了A鎖,順利執(zhí)行完一輪");
}
}
}
}
}
}
package Basic.src.com.Threadcase.ThreadSafe.DeadLock;
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("線程A");
t2.setName("線程B");
t1.start();
t2.start();
}
}
等待喚醒機(jī)制
生產(chǎn)者和消費(fèi)者
未講完

浙公網(wǎng)安備 33010602011771號