概念 實(shí)現(xiàn)方式 線程方法 線程同步 線程安全 線程死鎖 線程通訊 線程互斥鎖
概念
多線程:如果把QQ比作進(jìn)程,那么既聊天,又玩農(nóng)場(chǎng),就是多線程
并發(fā):甲任務(wù)與乙任務(wù)切換進(jìn)行
并行:甲任務(wù)與乙任務(wù)同時(shí)進(jìn)行
舉例:jvm是多線程,Jvm啟動(dòng)了垃圾回收線程和主線程
實(shí)現(xiàn)方式:三種
第一種---Thread類
public class HelloWorld {
public static void main(String[] args) {
//3、啟動(dòng)start
new thread().start();
for (int i=0;i<100000;i++){
System.out.println("主線程");
}
}
}
//1、繼承Thread
class thread extends Thread{
//2、實(shí)現(xiàn)run方法
public void run(){
for (int i=0;i<100000;i++){
System.out.println("副線程");
}
}
}
第二種---Runnable接口
public class HelloWorld {
public static void main(String[] args) {
//3、調(diào)用Thread類
Thread th = new Thread(new thread());
//4、啟動(dòng)start方法
th.start();
for (int i=0;i<100000;i++){
System.out.println("主線程");
}
}
}
//1、實(shí)現(xiàn)Runnable
class thread implements Runnable{
//2、實(shí)現(xiàn)run方法
public void run(){
for (int i=0;i<100000;i++){
System.out.println("副線程");
}
}
}
第三種---匿名方式
public class HelloWorld {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<100000;i++){
System.out.println("第一線程");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<100000;i++){
System.out.println("第二線程");
}
}
}).start();
}
}
線程方法
1、優(yōu)先級(jí) setPriority()
2、睡眠時(shí)間 sleep()
3、線程插隊(duì) join()
4、禮讓線程 yield()
5、后臺(tái)運(yùn)行 setDaemon(true)
public class HelloWorld {
public static void main(String[] args) {
Thread th=new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<100000;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一線程");
}
}
});
Thread th2=new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<100000;i++){
if (i == 9999){
try {
th.join();//線程插隊(duì)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i == 54654){
Thread.yield();//讓出CPU
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二線程");
}
}
});
th.setPriority(8);//從1-10 逐次增加
th.setDaemon(true);//設(shè)置守護(hù)線程(后臺(tái)運(yùn)行,占資源少)
th.start();
th2.start();
}
}
線程同步
package exercise;
/*
當(dāng)多線程并發(fā), 有多段代碼同時(shí)執(zhí)行時(shí), 我們希望某一段代碼執(zhí)行的過程中
CPU不要切換到其他線程工作,這時(shí)就需要同步。如果兩段代碼是同步的,
那么同一時(shí)間只能執(zhí)行一段, 在一段代碼沒執(zhí)行結(jié)束之前, 不會(huì)執(zhí)行另外一段
代碼。所謂同步代碼塊就是使用synchronized關(guān)鍵字加上一個(gè)鎖對(duì)象來定義
一段代碼,這就叫同步代碼塊,多個(gè)同步代碼塊如果使用相同的鎖對(duì)象,那
么他們就是同步的。
* */
class exercise{
//開始跑類方法
public static void main(String[] args) {
Print print=new Print();
new Thread(){
public void run(){
while(true){
print.print();
}
}
}.start();
new Thread(){
public void run(){
while(true){
print.print1();
}
}
}.start();
}
}
//創(chuàng)建對(duì)象,創(chuàng)建方法
class Print {
Demo demo=new Demo();
public void print(){
synchronized (demo) {
System.out.println("黑馬");
System.out.println("程序");
}
}
public void print1(){
synchronized(demo){
System.out.println("傳智");
System.out.println("博客");
}
}
}
//要跑的類
class Demo{}
線程安全
多線程安全問題:兩個(gè)線程在同時(shí)刻,只能其中一個(gè)參與運(yùn)算,另外一個(gè)必須等待。
通俗理解:兩個(gè)同學(xué)在餐廳同時(shí)搶第一個(gè)位置,結(jié)果自己想吧!
解決方法:給線程上鎖,在這個(gè)線程上鎖期間,不能有其他線程介入運(yùn)行,這樣就解決問題了!
public class HelloWorld {
public static void main(String[] args) {
new Ticket().start();
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}
class Ticket extends Thread{
private static int ticket = 100;
public void run(){
while (true){
//上鎖
synchronized (Ticket.class){
if(ticket<=0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
System.out.println(getName()+"第"+ ticket-- +"張票售出");
}
}
}
}
線程死鎖
/*一個(gè)線程持有鎖,沒釋放這個(gè)鎖之前,其他線程獲取不到此鎖,
如果其他線程非要此鎖,就要死等,這種情況,就是死鎖。
*/
線程通訊
等待:wait
單個(gè)喚醒:notify
全部喚醒:notifyAll
public class HelloWorld {
public static void main(String[] args) {
Ticket t = new Ticket();
new Thread(){
public void run(){
while (true){
try {
t.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while (true){
try {
t.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while (true){
try {
t.print3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
class Ticket {
private int ticket = 1;
public void print1() throws InterruptedException {
synchronized (this){
if (ticket != 1){
this.wait();//睡眠
}
System.out.println("線程一");
ticket=2;
this.notify();//喚醒
}
}
public void print2() throws InterruptedException {
synchronized (this){
if (ticket != 2){
this.wait();//睡眠
}
System.out.println("線程二");
ticket=3;
this.notify();//喚醒
}
}
public void print3() throws InterruptedException {
synchronized (this){
if (ticket != 3){
this.wait();//睡眠
}
System.out.println("線程三");
ticket=1;
this.notify();//喚醒
}
}
}
線程互斥鎖
ReentrantLock
Condition
/*
* 互斥鎖是JDK1.5版本的新特性,包含了多線程通訊、多線程鎖,比起之前的更具有靈活性。
*
* */
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class HelloWorld {
public static void main(String[] args) {
Ticket t = new Ticket();
new Thread(){
public void run(){
while (true){
try {
t.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while (true){
try {
t.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while (true){
try {
t.print3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
class Ticket {
private ReentrantLock r = new ReentrantLock();//互斥鎖
private Condition c1 = r.newCondition();//通訊1
private Condition c2 = r.newCondition();//通訊2
private Condition c3 = r.newCondition();//通訊3
private int ticket = 1;
public void print1() throws InterruptedException {
r.lock();//啟動(dòng)鎖
if (ticket != 1){
c1.await();//等待
}
System.out.println("線程一");
ticket=2;
c1.signal();//喚醒
r.unlock();//關(guān)閉鎖
}
public void print2() throws InterruptedException {
r.lock();//啟動(dòng)鎖
if (ticket != 2){
c2.await();//睡眠
}
System.out.println("線程二");
ticket=3;
c2.signal();//喚醒
r.unlock();//關(guān)閉鎖
}
public void print3() throws InterruptedException {
r.lock();//啟動(dòng)鎖
if (ticket != 3){
c3.await();//睡眠
}
System.out.println("線程三");
ticket=1;
c3.signal();//喚醒
r.unlock();//關(guān)閉鎖
}
}
線程組
//線程組:安全第一,A在1線程組內(nèi),A就不能修改2線程組數(shù)據(jù)。
//線程池:效率第一,A線程干完活,不結(jié)束他,讓他睡眠,需要再喚醒。
package exercise;
public class exercise {
public static void main(String[] args) {
ThreadGroup tg = new ThreadGroup("我是一個(gè)新線程");//創(chuàng)建線程組
MyRunnable mr = new MyRunnable();//創(chuàng)建Runnable的子類對(duì)象
Thread t1= new Thread(tg,mr,"張三");//將線程t1放在組中
Thread t2= new Thread(tg,mr,"李四");//將線程t2放在組中
System.out.println(t1.getThreadGroup().getName());//獲取組名
System.out.println(t2.getThreadGroup().getName());
}
}
class MyRunnable implements Runnable{
public void run() {
for(int i=0;i<100;i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
線程池
//一般我們創(chuàng)建少量線程,并不會(huì)出現(xiàn)太大問題,可是實(shí)際開發(fā)中我們
//可能要用到n多線程,頻繁創(chuàng)建和銷毀線程會(huì)嚴(yán)重銷毀系統(tǒng)資源,
//針對(duì)這一問題,出現(xiàn)了線程池技術(shù),線程池可以對(duì)線程回收再利用
package exercise;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class exercise {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);//第四步,創(chuàng)建線程池對(duì)象
pool.submit(new MyRunnable());//第五步,將線程放到池子里
pool.submit(new MyRunnable());
pool.shutdown();//第六步,關(guān)閉線程池
}
}
class MyRunnable implements Runnable{//第一步
public void run() {//第二步
for(int i=0;i<100;i++) {//第三步
System.out.println(Thread.currentThread().getName());
}
}
}
線程生命周期

123.png
線程定時(shí)器(Timer)
package exercise;
import java.io.IOException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
class exercise {
@SuppressWarnings("deprecation")
public static void main(String[] args) throws IOException, InterruptedException {
Timer t = new Timer();//第四步,創(chuàng)建計(jì)數(shù)器
t.schedule(new Time(), new Date(118,8,0,20,28,00));//new time();時(shí)間到了顯示起床啦
//new Data();設(shè)定時(shí)間
//年是2018-1900年
//月是9月
//日是1日
//時(shí)分秒 21點(diǎn) 23分 00秒
while(true) {//設(shè)定時(shí)間
Thread.sleep(1000);
System.out.println(new Date());
}
}
}
class Time extends TimerTask{//第一步
public void run() {//第二步
System.out.println("起床啦");//第三步
}
}