java多线程基础知识总结

时间:2023-02-26 18:32:00

                                         java多线程基础知识总结

一 线程的创建:

线程的创建一般是继承Thread类和实现Runnable接口两种方式:

1:由Thread类继承创建一个线程

创建一个普通java类,继承Thread类,重新写run方法,run方法即是线程体,放线程要执行的任务。然后创建该类的实例,实例调用start()方法开启一个线程。

package com.th;

public class ThreadEx extends Thread{
public ThreadEx(String threadName){
super(threadName);
}
public static void main(String[] args) {
ThreadEx te=new ThreadEx("A");
te.start();
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}

public void run(){

for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}

}


Thread(String threadName)给线程起个名字;

Thread.currentThread()获取当前线程的引用,可以获取线程名字也可以设置线程名字等。

程序中有两个线程,main线程是主线程和自己创建的一个线程,线程的执行是乱序的,每个线程获取cpu的时间片段也不同。

 

2:实现Runnable接口创建一个线程:

创建一个类,实现Runnable接口,重写run(),创建一个实现类的实例,创建Thread实例 new Thread(Runnable runnableImpl),用thread实例调用start()方法。

 

package com.th;

public class RunnableIm implements Runnable {

@Override
public void run() {
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}

}

public static void main(String[] args) {
RunnableIm ri=new RunnableIm();
Thread th=new Thread(ri);
th.setName("A");
th.start();
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}

}

通常用实现接口的方法获取一个线程。

二 线程的操作方法:

1 sleep(毫秒数)方法:

该方法是Thread的类的静态方法,让线程休眠指定的毫秒数,醒来继续执行。休眠时候仍然拥有对象的锁。在main()中是主线程休眠,在run中是当前线程休眠。会抛出InterruptedException异常,这也是结束一个线程的方法。

package com.th;

public class RunnableIm implements Runnable {

@Override
public void run() {
for(int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}

}

public static void main(String[] args) {
RunnableIm ri=new RunnableIm();
Thread th=new Thread(ri);
th.setName("A");
th.start();
for(int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}

}


2 中断一个线程的方法:

线程实例调用interrupt()方法,使得处于休眠或等待状态的线程抛出InterrruptedException 捕获改异常,进行处理使得run()运行完来结束线程,如改变循环的循环条件,结束执行循环运行完run();

 

 

package com.th;

public class RunnableIm implements Runnable {

@Override
public void run() {
for(int i=0;i<20;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block

break;
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
System.out.println("线程被打断了,结束运行!");
}

public static void main(String[] args) {
RunnableIm ri=new RunnableIm();
Thread th=new Thread(ri);
th.setName("A");
th.start();

try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
th.interrupt();
}

}


子线程一秒输出一次,主线程休眠5秒,之后打断子线程的执行。

 

3 线程的加入

join()方法,使得当前运行的线程阻塞,执行新加入的线程,直到新加入的线程执行完,原线程才能继续执行;

 

package com.th;

public class RunnableIm implements Runnable {

@Override
public void run() {
for(int i=0;i<20;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}

}

public static void main(String[] args) {
RunnableIm ri=new RunnableIm();
Thread th=new Thread(ri);
th.setName("A");
th.start();
for(int i=0;i<20;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
if(i==10){
try {
th.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

}


 

当main到10的时候,线程A加入了,线程A要执行完,main()线程才可以继续执行。

 

4 线程的礼让

yield() 让当前执行的线程暂停,重新参与cpu使用权的竞争,有可能还会继续执行(又抢到了cpu使用权);

 

package com.th;

public class RunnableIm implements Runnable {

@Override
public void run() {
for(int i=0;i<20;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}

}

public static void main(String[] args) {
RunnableIm ri=new RunnableIm();
Thread th=new Thread(ri);
th.setName("A");
th.start();
for(int i=0;i<20;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
if(i==10){
th.yield();
}
}
}

}


 

5 线程优先级

优先级高的首选得到cpu使用权,分的时间片段也会多,优先级1-10,默认为5

package com.th;

public class RunnableIm implements Runnable {

@Override
public void run() {
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}

}

public static void main(String[] args) {
RunnableIm ri=new RunnableIm();
Thread th=new Thread(ri);
Thread th1=new Thread(ri);
Thread th2=new Thread(ri);


th1.setPriority(5);
th1.setName("B");

th2.setPriority(1);
th2.setName("C");

th1.start();
th2.start();

}

}


 

 三 线程的生命周期

线程的生命周期包括:出生,就绪,运行, 等待、 休眠、 阻塞和死亡状态。

 创建Thread实例,线程进入了出生状态;

线程实例调用了start()方法,进入就绪状态;

就绪状态的线程得到cpu使用权进入运行状态;

运行状态可能进入等待、休眠和阻塞状态,这些状态结束可以回到就绪状态;

run运行完线程就进入了死亡状态。

 

四 线程的同步

多个线程使用同一资源,会带来安全问题:

package com.th;

public class Bank implements Runnable{
static int bankCount=3000;

public static void main(String[] args) {
Bank bank=new Bank();
Thread th1=new Thread(bank);
th1.setName("wife");
Thread th2=new Thread(bank);
th2.setName("husband");
th1.start();
th2.start();
}

@Override
public void run() {
if(bankCount>=2000){
System.out.println(Thread.currentThread().getName()+"取走2000元");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

bankCount-=2000;
}else{
System.out.println("余额不足");
}
}

}


 

丈夫和妻子同时取钱,妻子取走2000,线程休眠,账户还没减少,丈夫此时取钱,账户还是3000,故又取走2000元;

 

使用同步解决该问题:

package com.th;

public class Bank implements Runnable{
static int bankCount=3000;

public static void main(String[] args) {
Bank bank=new Bank();
Thread th1=new Thread(bank);
th1.setName("wife");
Thread th2=new Thread(bank);
th2.setName("husband");
th1.start();
th2.start();
}

@Override
public void run() {
synchronized(this){
if(bankCount>=2000){
System.out.println(Thread.currentThread().getName()+"取走2000元");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

bankCount-=2000;

}else{
System.out.println(Thread.currentThread().getName()+"余额不足");
}
}

}

}


 

给引出错误的代码加同步快,这段代码执行完毕其他线程才可以进入该段代码执行;

也可以给方法加synchronized,同步方法。一个时间一个对象只有一个同步方法执行,其他同步方法必须等到该同步方法执行完毕执行;

死锁:一个线程锁住了一个资源,企图锁住第二个资源,另外一个线程同时锁住了第二个资源,企图锁住第一个资源,形成死锁。死锁是打算锁定一个其他线程锁住的资源,而其他线程打算锁定自己锁定的资源,都处于等待同步快里的代码执行完毕;

package com.th;

public class Flock implements Runnable{
static Object obj1=new Object();
static Object obj2=new Object();
int flag;
public static void main(String[] args) {
Flock f1=new Flock();
Flock f2=new Flock();
f1.flag=1;
f2.flag=2;
new Thread(f1).start();
new Thread(f2).start();
}

@Override
public void run() {
if(flag==1){
synchronized (obj1) {
System.out.println("flag==1的线程锁住了obj1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (obj2) {
System.out.println("flag==1的线程锁住了obj2");
}
}


}else if(flag==2){
synchronized (obj2) {
System.out.println("flag==2的线程锁住了obj2");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (obj1) {
System.out.println("flag==2的线程锁住了obj1");
}
}
}

}

}


 

 五 生产者与消费者:

package com.th;

public class SX {

public static void main(String[] args) {
Lanzi lz=new Lanzi();
new Thread(new SC(lz)).start();
new Thread(new XF(lz)).start();
}

}
//苹果类
class Apple{
int id;
public Apple(int id){
this.id=id;
}
}

//篮子类,用来放苹果的
class Lanzi{
Apple[] lanzi=new Apple[10]; //苹果数组表示篮子,最多可以放10个苹果
int index=0; //篮子上的刻度,索引

//向篮子放苹果
public synchronized void putApple(Apple apple){
while(index==lanzi.length){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();
lanzi[index]=apple;
index++;
System.out.println("向篮子放入第"+apple.id+"个苹果");
}

//从篮子取出苹果
public synchronized Apple getApple(){
while(index==0){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();
index--;
System.out.println("吃掉第"+lanzi[index].id+"个苹果");
return lanzi[index];
}
}


class SC implements Runnable{
Lanzi lanzi;
public SC(Lanzi lz){
this.lanzi=lz;
}
@Override
public void run() {
for(int i=0;i<20;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Apple a=new Apple(i+1);
lanzi.putApple(a);
}


}


}


class XF implements Runnable{
Lanzi lanzi;
public XF(Lanzi lz){
this.lanzi=lz;
}
@Override
public void run() {
for(int i=0;i<20;i++){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

lanzi.getApple();
}


}


}

 

 

六 wait和sleep

wait 是Object方法,进入等待的线程不再拥有对象的锁,需要该对象上其他线程调用notify()或notifyAll()唤醒,自己不能唤醒自己;

sleep 是Thread的静态方法,休眠指定时间会苏醒,自始至终会拥有锁。

 

 

七 线程池

单独创建使用销毁多个线程会使用较多的系统资源,线程池可以对线程进行统一管理,避免自己创建线程过度的开销。

Executors调用newCachedThreadPool创建一种缓存线程池,该线程池可以对空闲线程灵活回收,若无回收则新建线程;

package com.th;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TP {

public static void main(String[] args) {
TH1 th1=new TH1();
TH2 th2=new TH2();
ExecutorService cachedThreadPool=Executors.newCachedThreadPool();
cachedThreadPool.execute(th1);
cachedThreadPool.execute(th1);
}

}

class TH1 implements Runnable{

@Override
public void run() {
for(int i=1;i<10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}

}

}

class TH2 implements Runnable{

@Override
public void run() {
for(int i=1;i<10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}

}

}