线程的创建
- 线程开启不一定立即执行,会与主线程交替执行,由cpu调度。
- 推荐使用实现Runnable接口,避免单继承局限性,方便同一个对象被多个线程使用。
- 多个线程操作同一个资源,线程不安全,数据紊乱。
继承Thread类
public class Thread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("aaa"+i);
}
}
public static void main(String[] args) {
//创建线程对象
Thread1 t = new Thread1();
//调用start()方法,开启线程
t.start();
for (int i = 0; i < 20; i++) {
System.out.println("bbb"+i);
}
}
}
实现Runnable接口
public class Thread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//使线程休眠200纳秒
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("aaa"+i);
}
}
public static void main(String[] args) {
//创建线程对象
Thread2 t = new Thread2();
//调用start()方法,开启线程
new Thread(t).start(); //可以new Thread(t,"小明").start();小明是这个线程的名字
for (int i = 0; i < 20; i++) {
System.out.println("bbb"+i);
}
}
}
实现Callable接口
import java.util.concurrent.*;
public class Test {
public static void main(String[] args) {
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread());
new Thread(futureTask).start();
try {
Integer integer = futureTask.get();
System.out.println(integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("MyThread");
return 100;
}
}
静态代理
- 真实对象和代理对象都要实现同一个接口
- 代理对象要代理真实角色
- 代理对象可以做真实对象做不了的事
public class Test{
public static void main(String[] args) {
WeddingCompany wc = new WeddingCompany(new You());
wc.HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
//真实角色类
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("结婚");
}
}
//代理类
class WeddingCompany implements Marry{
private Marry marry;
public WeddingCompany(Marry marry) {
this.marry = marry;
}
@Override
public void HappyMarry() {
before();
this.marry.HappyMarry();
after();
}
private void before() {
System.out.println("结婚前");
}
private void after() {
System.out.println("结婚后");
}
}
lambda表达式写线程
new Thread(
()-> System.out.println("我爱你") //lambda表达式简化一个接口中唯一需要被实现的方法,在这里是run();
).start();
线程方法
线程停止
线程停止一般使用自定义的方法
public class Thread2 implements Runnable {
//设置标识位
private boolean flag = true;
@Override
public void run() {
while(flag){
System.out.println("方法");
}
}
//自定义停止方法
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
Thread2 t =new Thread2();
new Thread(t).start();
t.stop(); //停止线程
}
}
线程休眠
- 每个对象都有一个锁,线程休眠不会释放锁
- 线程休眠可以放大问题细节
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
线程礼让
使运行中的线程转为就绪状态,cpu重新选择线程调度,礼让不一定成功,cpu也可能还是选择礼让的线程。
A运行中,B就绪,A礼让,A就绪,cpu重新选择A运行还是B运行
Thread.yield();
线程插队
线程插队由线程对象执行,强制执行要求的线程,执行完再执行主线程。
Thread thread =new Thread();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
观察线程状态
Thread.State state = thread.getState(); //thread是线程对象,可直接输出state
线程可以处于以下状态之一:
NEW 尚未启动的线程处于此状态。
RUNNABLE 在Java虚拟机中执行的线程处于此状态。
BLOCKED 被阻塞等待监视器锁定的线程处于此状态。
WAITING 正在等待另一个线程执行特定动作的线程处于此状态。
TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
TERMINATED 已退出的线程处于此状态。
一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。
返回当前线程对象及其名字
Thread.currentThread(); //返回当前线程对象
Thread.currentThread().getName(); //返回当前线程对象名字
线程优先级
-
线程优先级高不一定先执行,但是先执行的概率更大,优先级1~10。
-
线程要先设置优先级再启动,一般不设置,默认5。
Thread.getPriority(); //查看线程优先级
thread.setPriority(6); //设置线程优先级
守护线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕,一般指main()
- 虚拟机不用等待守护线程执行完毕就可以停止
- 如后台记录操作日志,监控内存,垃圾回收等
thread.setDaemon(true); //默认为false表示用户线程,正常的线程都是用户线程,设置为true表示守护线程
线程同步
解决多个线程操作同一个资源,线程不安全,数据紊乱问题。
synchronized 关键字
监视方法内的对象
class BuyTicket implements Runnable{
int ticketNums = 100000;
@Override
public void run() {
buy();
}
private synchronized void buy() {
while(true){
if(ticketNums>0){
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+":"+ticketNums--);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
}
}
}
synchronized(监视线程对象){方法}
import java.util.List;
public class SellTicket implements Runnable{
int tickets=100;
public void run() {
while(true) {
synchronized(this) {
if(tickets>0) {
try {
Thread.sleep(0);
}
catch(Exception x) {}
System.out.println(Thread.currentThread().getName()+" 售出票 "+tickets--);
}
else {
break;
}
}
}
}
}
Lock锁
可重用锁,显示定义同步锁,使用Lock对象。
使用ReentrantLock创建锁对象
ReentrantLock lock = new ReentrantLock();
开启锁
try{
lock.lock();
}
关闭锁
finally {
lock.unlock();
}
实例
import java.util.concurrent.locks.ReentrantLock;
public class Test {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket, "a").start();
new Thread(buyTicket, "b").start();
new Thread(buyTicket, "c").start();
}
}
class BuyTicket implements Runnable {
int ticketNums = 10;
//使用ReentrantLock创建锁对象
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
//开启锁
lock.lock();
if (ticketNums > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + ticketNums--);
} else {
break;
}
} finally {
//关闭锁
lock.unlock();
}
}
}
}
线程协调
一般在synchronized同步代码块里使用wait()、notify/notifyAll()方法。
wait()
- 线程等待,会释放锁,释放资源,sleep不会。
- wait()需要被try…catch包围。
this.wait();
this.wait(long timeout);
notify()
唤醒线程
this.notify();
this.notifyAll(); //唤醒所有等待的线程
生产者消费者问题
管程法
/*
测试生产者消费者模型-->利用缓冲区解决:管程法
生产者,消费者,产品,缓冲区
*/
public class Test {
public static void main(String[] args) {
SysContainer container = new SysContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生产者类
class Productor extends Thread {
SysContainer container;
public Productor(SysContainer container) {
this.container = container;
}
//生产鸡!
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("生产了" + i + "只鸡");
container.push(new Chicken(i));
}
}
}
//消费者类
class Consumer extends Thread {
SysContainer container;
public Consumer(SysContainer container) {
this.container = container;
}
//消费者消费
@Override
public void run() {
//消费
for (int i = 0; i < 100; i++) {
System.out.println("消费了-->" + container.pop().id + "只鸡");
}
}
}
//产品类
class Chicken {
int id;//生产编号
public Chicken(int id) {
this.id = id;
}
}
class SysContainer {
//设定容器大小
Chicken[] chickens = new Chicken[9];
//容器计数器
int count = 0;
//消费者负责生产鸡
public synchronized void push(Chicken chicken) {
//如果生产的鸡到达了容器大小,停止生产等待消费者消费
if (count == chickens.length) {
//生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//容器没有满,就放入产品
chickens[count] = chicken;
count++;
//通知消费者消费
this.notifyAll();
}
//消费者消费
public synchronized Chicken pop() {
//判断是否有鸡
if (count == 0) {
try {
//没有鸡等待
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有鸡就可以消费
count--;
Chicken chicken = chickens[count];
//唤醒生产者生产
this.notifyAll();
return chicken;
}
}
信号灯法
//解决生产者消费者问题方法2:信号灯法
public class TestPC2 {
public static void main(String[] args) {
TV tv =new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生产者:演员
class Player extends Thread{
TV tv;
public Player(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2==0){
this.tv.play("快乐大本营");
}else{
this.tv.play("斗鱼");
}
}
}
}
//消费者:观众
class Watcher extends Thread{
TV tv;
public Watcher(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//产品:电视节目
class TV{
//演员表演,观众等待 T
//观众观看,演员等待 F
String voice;
boolean flag =true;
public synchronized void play(String voice){
//观众观看,演员等待
if (!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//若观众没看,演员表演
System.out.println("演员表演了"+voice);
//通知观众看
this.notifyAll();
this.voice=voice;
this.flag=!this.flag;
}
//观看方法
public synchronized void watch(){
//演员表演观众等待
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观看了:"+voice);
//通知演员表演
this.notifyAll();
this.flag=!this.flag;
}
}
线程池
- 提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。
- 可以避免频繁创建销毁、实现重复利用。
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理,如:
-
corePoolSize:核心池的大小
-
maximumPoolSize:最大线程数广
-
keepAliveTime:线程没有任务时最多保持多长时间后会终止
ExecutorService
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
//创建线程池,参数是线程数量,此处为10
ExecutorService executorService = Executors.newFixedThreadPool(10);
//放入线程
executorService.execute(new MyThread());
executorService.execute(new MyThread());
//关闭线程池
executorService.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}