目录
建议使用定义2,实现Runnable的好处:多个线程跑同一个对象。直接继承Thread,一个对象只能被继承Thread的子类使用。
Thread
线程定义
使用同一对象生成的线程共享对象内资源。
定义方法1
自定义线程类需要继承Thread类并重写run()方法
public class SonThread extends Thread{
public void run(){
//线程体
}
public static void main(String[]args){
//创建线程对象并开启线程
SonThread s = new SonThread();
s.start();
}
}
定义方法2:
实现Runnable接口,实现run()方法,创建线程对象
public class Run1 implements Runnable{
public void run(){
}
}
public class Main{
public static void main(String[]args){
Thread thread1 = new Thread(new Run1());
}
}
建议使用定义2,实现Runnable的好处:多个线程跑同一个对象。直接继承Thread,一个对象只能被继承Thread的子类使用。
例子:
//多线程操作同一个对象 买火车票的例子
public class TestThreadDemo01 implements Runnable{
//这个类可以看成一个票站,每个线程看成买票的。
private int ticketNums ; //票的数量
public TestThreadDemo01(int ticketNums) {
this.ticketNums = ticketNums;
}
@Override
public void run(){
while(true){
if(ticketNum <=0){
break;
}
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 拿到了第 "+ ticketNum -- + "张票");
}
}
public static void main(String[] args) {
TestThreadDemo01 testThreadDemo01 = new TestThreadDemo01(10); //生成一个拥有10张票的票站
new Thread(testThreadDemo01,"张三").start(); //买票
new Thread(testThreadDemo01,"李四").start();
new Thread(testThreadDemo01,"王五").start();
}
}
龟兔赛跑
public class Race implements Runnable {
//该类就像一条赛道
//赛道长度
private int length;
//是否跑完
private static boolean flag = false;
public Race(int length) {
this.length = length;
}
private static String winner; //注意得static 不然会有两个winner
@Override
public void run() {
int i;
for (i =1; i <=length;i++){
//是否结束
if(flag == true)
break;
//兔子快到终点时睡觉
if(i == 80 && Thread.currentThread().getName() == "兔子") {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 跑了 " + i + " 米");
}
//结束
if(i == 101){
flag = true;
winner = Thread.currentThread().getName();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("winner: " + winner);
}
}
public static void main(String[] args) {
Race race = new Race(100); //生成100m的赛道
new Thread(race,"兔子").start(); //兔子乌龟上赛道
new Thread(race,"乌龟").start();
}
}
lamda表达式
任何接口,如果是只包含唯一一个抽象方法,那么它就是函数式接口。
函数式接口可以通过lamda表达式来创建接口。
lamda表达式是匿名内部类的简写
new Thread( (/*参数*/)->{//重写run方法} ).start();
参数类型、小括号、大括号可以适时忽略。参数不能忽略
lamda表达式的演变
public class Lamda {
public static void main(String[] args) {
interfaceWith1Method a1 = (int a)-> {System.out.println("hello" + a)};
interfaceWith1Method a2 = new interfaceWith1Method() {
@Override
public void Method(int a) {
System.out.println("hello" + a);
}
};
a1.Method(1);
a2.Method(2);
}
}
interface interfaceWith1Method{
abstract void Mehod(int a);
}
线程状态
停止线程
//让线程停止的方法
//1.建议线程正常停止, 利用次数,不建议死循环
//2.设置标志位flag。
//3.不使用stop或destroy等过时方法或JDK不建议的方法
public class TestStop implements Runnable{
//此例使用标志位法
private boolean flag = true;
@Override
public void run() {
int i = 0;
while(flag){
System.out.println("thread---run:" + i++);
}
}
public void stop(){
flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 1000; i++){
System.out.println("main" + i);
if(i == 900){
testStop.stop();
System.out.println("线程停止");
}
}
}
}
线程休眠
Thread.sleep(100/*毫秒*/);
//提高线程发生的可能性
sleep不会释放锁。
线程礼让
礼让线程,让当前线程暂停,但是不阻塞。
暂停:由运行状态进入就绪状态,等待cpu调度。
调度结果看CPU
线程强制执行Join
类似插队
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 1; i++){
System.out.println("我插队来了" + i);
}
}
public static void main(String[] args) throws Exception {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 1; i <= 10; i++){
if (i == 5)
thread.join(); //线程强制执行
System.out.println("main 正在运行" + i);
}
}
}
线程状态
Thread.State
public class TestThreakState implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1; i++) { //休眠等待。
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("--------");
}
public static void main(String[] args) throws Exception {
TestThreakState testThreakState = new TestThreakState();
Thread thread = new Thread(testThreakState);
System.out.println(thread.getState()); //创建状态
thread.start(); //线程运行
while(thread.getState() != Thread.State.TERMINATED){
Thread.sleep(300);
System.out.println(Thread.currentThread().getName() + " " +Thread.currentThread().getState());//自己的线程状态
System.out.println(thread.getName()+" "+thread.getState());
//获取另一条线程的状态
}
}
}
线程优先级
优先级(1~10)高只是意味着被调度的概率高
获取和设置.getPriority() .setPriority(int x);
public class TestPriority {
public static void main(String[] args) {
Runnable thread = new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+ "-->" + Thread.currentThread().getPriority());
}
}; //创建一个 Runnable对象
//创建线程并设置优先级
Thread thread1 = new Thread(thread);
thread1.setPriority(1);
Thread thread2 = new Thread(thread);
thread2.setPriority(5);
Thread thread3 = new Thread(thread);
thread3.setPriority(10);
thread3.start();
thread2.start();
thread1.start();
}
}
守护线程
线程分为守护线程和用户线程。
虚拟机不用等待守护线程执行完毕,用户线程停止,虚拟机停止工作。
设置守护线程
thread.setDaemon(true);
线程同步机制(锁)
多个线程访问同一个对象,需要排队、加锁。
队列
锁(synchronized)(隐式)
同步方法
加了synchronized的方法必须获得调用该方法的对象的锁才能执行,否则线程会阻塞。方法一旦执行,就会独占锁。直到方法结束,才释放锁。
synchronized默认锁的对象是this,类本身。
两种锁的方法
public class TestAccount implements Runnable{
@Override
//锁的是TestAccount对象
public synchronized void run() {
}
}
public class TestAccount implements Runnable{
@Override
public void run() {
synchronized(/*要锁的对象*/){
/*代码块*/
}
}
}
例子:
//多线程操作同一个对象
public class TestThreadDemo01 implements Runnable{
//这个类可以看成一个票站,每个线程看成买票的。
private int ticketNum ; //票的数量
public TestThreadDemo01(int ticketNum) {
this.ticketNum = ticketNum;
}
@Override
public void run(){
while(true){
synchronized (this){
if(ticketNum <=0){
break;
}
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
" 拿到了第 "+ ticketNum -- + " 张票");
}
}
}
public static void main(String[] args) {
TestThreadDemo01 testThreadDemo01 = new TestThreadDemo01(10);
//生成一个拥有10张票的票站
new Thread(testThreadDemo01,"张三").start(); //买票
new Thread(testThreadDemo01,"李四").start();
new Thread(testThreadDemo01,"王五").start();
Thread thread = new Thread(()->{
System.out.println(1);
});
}
}
死锁
多个线程占有一些共享资源;线程等待其他线程释放资源而停止执行的情形,叫做死锁。
当某一同步块拥有两个以上锁时,可能产生死锁。
产生的四个条件
1.互斥:一个资源每次只能被一个线程调用。
2.请求与保持:一个线程因阻塞而等待,对已获得的资源保持不放。
3.不剥夺:线程获得的资源,在未使用完之前不得被剥夺
4.循环等待:若干线程之间形成一种头尾相接的循环等待资源关系。
Lock锁(显式)
public class TestLock implements Runnable{
int ticketNums;
ReentrantLock lock = new ReentrantLock();
public TestLock(int ticketNums) {
this.ticketNums = ticketNums;
}
@Override
public void run() {
while(true){
try {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock(); //锁
if(ticketNums >= 1)
System.out.println(Thread.currentThread().getName()+" " + ticketNums --);
else
break;
}finally {
lock.unlock(); //开锁
}
}
}
public static void main(String[] args) {
TestLock testLock = new TestLock(10);//10张票
new Thread(testLock,"张三").start();
new Thread(testLock,"李四").start();
new Thread(testLock,"王五").start();
}
}
线程协作(生产消费)
wait()和notify()。
wait() :导致当前线程等待,直到另一个线程调用该对象的notify()或者notifyAll()方法
注意:wait()和notify()只能在同步方法(synchronized)中使用。
public class TestPV {
public static void main(String[] args) {
Containner containner = new Containner(10);//生成一个100的缓冲区
new Producer(containner).start();
new Consumer(containner).start();
}
}
//产品类
class Produce {
int id;
public Produce(int id) {
this.id = id;
}
}
//生产者类
class Producer extends Thread {
Containner containner;
public Producer(Containner containner) {
this.containner = containner;
}
@Override
public void run() {
int i = 1;
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
containner.pop(new Produce(i)); //往容器里放产品
i++;
}
}
}
//消费者类
class Consumer extends Thread {
Containner containner;
public Consumer(Containner containner) {
this.containner = containner;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
containner.push();
}
}
}
//缓冲区
class Containner {
int maxNum; //缓冲区大小
int currentNum = 0;
Produce[] containner;
public Containner(int maxNum) {
this.maxNum = maxNum;
containner = new Produce[maxNum];
}
//缓冲区
//生产者放入产品
public synchronized void pop(Produce produce) {
if (currentNum < maxNum) {
containner[currentNum] = produce;
System.out.println("生产" + produce.id);
currentNum++;
notifyAll();//提醒有产品了
} else {
try {
System.out.println("产品满了");
wait();//产品满了
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//消费者拿出产品
public synchronized void push() {
//判断有没有产品
if (currentNum > 0) {
currentNum--;
System.out.println("消费了产品" + containner[currentNum].id);
notifyAll(); //提醒 我已经消费了
} else {
try {
System.out.println("产品不足");
wait(); //产品不足
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程池
线程用完之后不用销毁,放回线程池。避免了生成销毁线程造成的资源浪费。
思路:创建多个线程,放入线程池中,使用时获取线程,使用完后放回线程池。
好处:提高响应速度,降低资源消耗,便于管理。
shutdown();不再接受线程任务。不是停止。
线程池例子:
public class TestPool {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
//new个线程池
service.execute(new MyThread()); //将继承了Runnable的类的对象放入
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.shutdown(); //不再接受任务
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}