多线程机制
1.1 线程的基本概念
1.1.1 线程是程序里不同的执行路径
2.1 线程的创建
2.1.1 继承Thread类
2.1.2 实现runnable接口(推荐使用)
3.1 线程的调度和优先级
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。
线程调度器按照线程的优先级决定应调度那个线程来执行。
优先级越高,获得的时间片长度越多。
线程优先级用数字表示,范围从1到10,一个线程的缺省优先级是5。
Thread.MIN_PRIORITY=1
Thread.MAX_PRIORITY=10
Thread.NORM_PRIORITY=5
使用下述方法获得或设置线程对象的优先级
int getPriority();
4.1 线程状态控制
5.1.1 当用synchronized来修饰一个方法或代码块的时候,能够保证在同一时刻最多只能只有
一个线程执行该段代码
5.1.2 当两个并发线程访问同一对象object中的这个synchronized(this)同步代码块时,一个时间内
只能有一个线程得到执行。另外一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
5.1.3 当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该
object的非synchronized(this)同步代码块
5.1.4 *当一个线程访问object的一个synchronize(this)代码块,其他线程对该object中所有其他
synchronized(this)同步代码块的访问将被阻塞
5.1.5 synchronized同步方法、synchronized同步方法块
5.1.6 死锁就是指多个进程(线程)因竞争资源(系统资源竞争、程序推进顺序非法)而造成的一种僵局
1.线程的基本概念
2.线程的创建
3.线程的调度和优先级
4.线程的状态控制
5.线程同步
1.1 线程的基本概念
1.1.1 线程是程序里不同的执行路径
2.1 线程的创建
2.1.1 继承Thread类
2.1.2 实现runnable接口(推荐使用)
3.1 线程的调度和优先级
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。
线程调度器按照线程的优先级决定应调度那个线程来执行。
优先级越高,获得的时间片长度越多。
线程优先级用数字表示,范围从1到10,一个线程的缺省优先级是5。
Thread.MIN_PRIORITY=1
Thread.MAX_PRIORITY=10
Thread.NORM_PRIORITY=5
使用下述方法获得或设置线程对象的优先级
int getPriority();
void setPriority();
涉及优先级的demo(线程优先级越高,分配的时间片相对越长):
public class TestPriority {
public static void main(String[] args) {
Runnable runnable1=new T1();
Runnable runnable2=new T2();
Thread thread1=new Thread(runnable1);
Thread thread2=new Thread(runnable2);
thread1.setPriority(Thread.NORM_PRIORITY+3);
thread1.start();
thread2.start();
}
}
class T1 implements Runnable{
public void run() {
for(int i=0;i<1000;i++){
System.out.println("T1: "+i);
}
}
}
class T2 implements Runnable{
public void run() {
for(int i=0;i<1000;i++){
System.out.println("T2: "+i);
}
}
}
4.1 线程状态控制
4.1.1 sleep()方法 (让当前线程休眠)(如何优雅地关掉一个线程 interrupt、stop、通过标志位【推荐】)
import java.util.Date;
/*sleep用法*/
public class TestInterrupted {
public static void main(String[] args) {
Runnable thread = new Mythread1();// 创建线程
Thread mythread=new Thread(thread);
mythread.start();// 使线程处于就绪状态
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
mythread.interrupt();
}
}
/*
* 推荐使用--通过实现接口来实现Thread的创建
* 1.1 java里面只有单继承,这样线程类的灵活性更好
*/
class Mythread1 implements Runnable{
public void run() {
while(true) {
System.out.println("---" + new Date() + "---");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 捕捉到异常时退出
return;
}
}
}
}
**如何优雅关闭一个线程:
public class TestThread1 {
public static void main(String[] args) {
Runner1 runner1=new Runner1();
Thread thread=new Thread(runner1);
thread.start();
for(int i=0;i<100000;i++){
if(i%10000==0&&i>0){
System.out.println("in main thread i="+i);
}
}
System.out.println("thread main is over");
//thread.stop(); //不推荐使用stop()
runner1.shutDown();
}
}
class Runner1 implements Runnable{
//如何地优雅关闭某个线程:实质就是优雅停止执行线程的方法体:run()
private boolean flag=true;
public void run() {
int i=0;
while(flag==true){
System.out.println("i: "+i++);
}
}
public void shutDown(){
flag=false;
}
}
4.1.2 join()方法 (合并某个线程)
public class TestJoin {
public static void main(String[] args) {
Runnable runnable=new Mythread2();
Thread thread=new Thread(runnable);
thread.setName("thread1");
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=1;i<=10;i++){
System.out.println("i am main thread");
}
}
}
class Mythread2 implements Runnable{
public void run() {
for(int i=1;i<=10;i++){
System.out.println("i am "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4.1.3 yield()方法 (让出cpu,给其他线程执行的机会)
public class TestYield {
public static void main(String[] args) {
Runnable runnable=new MyThread3();
Thread thread1=new Thread(runnable);
Thread thread2=new Thread(runnable);
thread1.start();
thread2.start();
for(int i=0;i<20;i++){
System.out.println("mainThread"+": "+i);
if(i%10==0){
Thread.yield();
}
}
}
}
class MyThread3 implements Runnable{
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName()+": "+i);
if(i%10==0){
Thread.yield();
}
}
}
}
4.1.4 wait()方法 、notify()/notifyAll()方法(配对使用、前提:获得锁)
wait():
notify():
经典的消费者生产者问题:
public class ProductComsumer {
public static void main(String[] args) {
SyncStack stack=new SyncStack();
Producter producter=new Producter(stack);
Comsumer comsumer=new Comsumer(stack);
new Thread(producter).start();
new Thread(comsumer).start();
}
}
//馒头类
class WoTou{
private int id;
public WoTou(int id){
this.id=id;
}
public String toString(){
return "WoTou : "+id;
}
}
//蒸笼类
class SyncStack{
private int index=0;
private WoTou[] arrWT=new WoTou[6];
//生产馒头
public synchronized void push(WoTou wt){
while(index==arrWT.length){
try {
this.wait(); //停止生产馒头
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify(); //通知消费馒头
arrWT[index]=wt;
index++;
}
//消费馒头
public synchronized WoTou pop(){
while(index==0){
try {
this.wait(); //停止消费馒头
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify(); //通知生产馒头
index--;
return arrWT[index];
}
}
//生产者类
class Producter implements Runnable{
private SyncStack stack=null;
public Producter(SyncStack stack){
this.stack=stack;
}
public void run() {
WoTou woTou=null;
for(int i=0;i<20;i++){
woTou=new WoTou(i);
stack.push(woTou);
System.out.println("生产了:"+woTou);
try {
Thread.sleep((int)Math.random()*1000);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
//消费者类
class Comsumer implements Runnable{
private SyncStack stack=null;
public Comsumer(SyncStack stack){
this.stack=stack;
}
public void run() {
WoTou woTou=null;
for(int i=0;i<20;i++){
woTou=stack.pop();
System.out.println("消费了:"+woTou);
try {
Thread.sleep((int)Math.random()*1000);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
5.1 线程同步5.1.1 当用synchronized来修饰一个方法或代码块的时候,能够保证在同一时刻最多只能只有
一个线程执行该段代码
5.1.2 当两个并发线程访问同一对象object中的这个synchronized(this)同步代码块时,一个时间内
只能有一个线程得到执行。另外一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
5.1.3 当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该
object的非synchronized(this)同步代码块
5.1.4 *当一个线程访问object的一个synchronize(this)代码块,其他线程对该object中所有其他
synchronized(this)同步代码块的访问将被阻塞
5.1.5 synchronized同步方法、synchronized同步方法块
5.1.6 死锁就是指多个进程(线程)因竞争资源(系统资源竞争、程序推进顺序非法)而造成的一种僵局
5.1.7 死锁产生的必要条件:互斥条件、不可剥夺条件、请求和保持条件、循环等待链条件
线程同步demo:
public class TestSync implements Runnable {
Timer timer=new Timer();
public static void main(String[] args) {
TestSync test=new TestSync();
Thread thread1=new Thread(test);
Thread thread2=new Thread(test);
thread1.setName("t1");
thread2.setName("t2");
thread1.start();
thread2.start();
}
public void run() {
timer.add(Thread.currentThread().getName());
}
}
class Timer {
private static int num = 0;
public void add(String name) {
synchronized (this) {
num++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
System.out.println(name + ",你是第" + num + "个使用timer的线程");
}
}
}
线程死锁:
public class DeadLock {
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = new Object();
Thread t1 = new T1(o1,o2);
Thread t2 = new T2(o1,o2);
t1.start();
t2.start();
}
}
class T1 extends Thread{
Object o1;
Object o2;
T1(Object o1,Object o2){
this.o1 = o1;
this.o2 = o2;
}
public void run() {
synchronized (o1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
}
}
}
}
class T2 extends Thread{
Object o1;
Object o2;
T2(Object o1,Object o2){
this.o1 = o1;
this.o2 = o2;
}
public void run() {
synchronized (o2) {
synchronized (o1) {
}
}
}
}
经典多线程面试题
public class TT implements Runnable{
private int b=100;
public synchronized void m1() throws Exception{
b=1000;
Thread.sleep(5000);
System.out.println("b = "+b);
}
// 1.
public void m2() throws Exception{
Thread.sleep(2500);
b=2000;
}
// 2.
// public synchronized void m2() throws Exception{
// Thread.sleep(2500);
// b=2000;
// }
public void run() {
try {
m1();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
TT tt=new TT();
Thread t=new Thread(tt);
t.start();
tt.m2();
System.out.println(tt.b);
}
}