线程的三种创建方式
:
1:继承Thread类
//创建线程的快捷方式一:继承Thread,重写run方法,调用start开启线程;
//总结:注意线程开启不一定执行,由cpu调度执行
public class TestThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码=="+i);
}
}
public static void main(String[] args) {
TestThread1 testThread1=new TestThread1();
testThread1.start();
for (int i = 0; i < 2000; i++) {
System.out.println("我在学习多线程=="+i);
}
}
}
//练习Thread,实现多线程下载图片
public class TestThread2 extends Thread{
private String name;
private String url;
public TestThread2(String name, String url) {
this.name = name;
this.url = url;
}
@Override
public void run() {
WebDownloader webDownloader=new WebDownloader();
webDownloader.downloader(name,url);
System.out.println("下载文件名为"+name);
}
public static void main(String[] args) {
TestThread2 testThread1=new TestThread2("1.jpg","https://img0.baidu.com/it/u=648074082,2528336694&fm=253&fmt=auto&app=138&f=JPEG?w=960&h=491");
TestThread2 testThread2=new TestThread2("2.jpg","https://img1.baidu.com/it/u=1690337816,4247323366&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=701");
TestThread2 testThread3=new TestThread2("3.jpg","https://img2.baidu.com/it/u=638721022,3403685495&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500");
testThread1.start();
testThread2.start();
testThread3.start();
}
}
class WebDownloader{
public void downloader(String name, String url){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("io异常");
}
}
}
不建议使用:避免oop单继承局限性;
2:实现Runnable接口
public class TestThread3 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码=="+i);
}
}
public static void main(String[] args) {
TestThread3 testThread3=new TestThread3();
new Thread(testThread3).start();
for (int i = 0; i < 2000; i++) {
System.out.println("我在学习多线程=="+i);
}
}
}
推荐使用:避免单继承局限性,零活方便,方便同一个对象被多个线程使用;
抢票案例:
public class TestThread4 implements Runnable {
private int ticketNums=10;
@Override
public void run() {
while (true){
if (ticketNums<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"票");
}
}
public static void main(String[] args) {
TestThread4 testThread4=new TestThread4();
new Thread(testThread4,"小王").start();
new Thread(testThread4,"小张").start();
new Thread(testThread4,"小志").start();
}
}
龟兔赛跑案例:
public class Race implements Runnable {
private static String winner;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean b = gameOver(i);
if (b==true){
break;
}
System.out.println(Thread.currentThread().getName()+"已经跑了"+i+"步");
}
}
private boolean gameOver(int steps){
if (winner!=null){
return true;
}
if (steps>=100){
winner=Thread.currentThread().getName();
System.out.println("WINNER IS "+winner);
return true;
}else {
return false;
}
}
public static void main(String[] args) {
Race race=new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
3:Callable接口
public class TestCallable implements Callable {
String url;
String name;
public TestCallable(String name, String url) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() throws Exception {
WebDownloader webDownloader=new WebDownloader();
webDownloader.downloader(name,url);
System.out.println("下载文件名为"+name);
return true;
}
class WebDownloader {
public void downloader(String name, String url) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("io异常");
}
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable testThread1=new TestCallable("1.jpg","https://img0.baidu.com/it/u=648074082,2528336694&fm=253&fmt=auto&app=138&f=JPEG?w=960&h=491");
TestCallable testThread2=new TestCallable("2.jpg","https://img1.baidu.com/it/u=1690337816,4247323366&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=701");
TestCallable testThread3=new TestCallable("3.jpg","https://img2.baidu.com/it/u=638721022,3403685495&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500");
//创建服务
ExecutorService executorService= Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> result1=executorService.submit(testThread1);
Future<Boolean> result2=executorService.submit(testThread2);
Future<Boolean> result3=executorService.submit(testThread3);
//获取结果
Boolean aBoolean = result1.get();
Boolean aBoolean2 = result2.get();
Boolean aBoolean3 = result3.get();
//关闭服务
executorService.shutdownNow();
}
}
静态代理
public class StacticProxy {
public static void main(String[] args) {
ZhongJie zhongJie=new ZhongJie(new Mine());
zhongJie.Sleep();
}
}
interface ZuFang {
void Sleep();
}
class Mine implements ZuFang {
@Override
public void Sleep() {
System.out.println("租房是为了晚上有睡觉的地方");
}
}
class ZhongJie implements ZuFang{
private Mine mine;
ZhongJie(Mine mine) {
this.mine = mine;
}
@Override
public void Sleep() {
before();
mine.Sleep();
after();
}
private void before(){
System.out.println("中介找房源");
}
private void after(){
System.out.println("事成签合同");
}
}
总结:真实对象和代理对象必须实现同一个接口;
代理对象代理真实对象;
Lamda表达式
理解函数式接口,是学习lamda表达式的关键所在;
函数式接口的定义:
1 任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口;
public interface Runnable {
public abstract void run();
}
2 对于函数式接口,我们可以通过lambda来创建该接口的对象;
详列:
public class TestLamdba1 {
//3 静态内部类
static class Like2 implements ILike {
@Override
public void lamdba() {
System.out.println("I like lambda 2");
}
}
public static void main(String[] args) {
//4 局部内部类
class Like3 implements ILike{
@Override
public void lamdba() {
System.out.println("i like lambda3");
}
}
//5 匿名内部类
ILike like4 = new ILike() {
@Override
public void lamdba() {
System.out.println("i like lambda4");
}
};
like4.lamdba();
ILike like = new Like();
like.lamdba();
ILike like2 = new Like2();
like2.lamdba();
ILike like3 = new Like3();
like3.lamdba();
//6 用lambda简化
ILike like6=new Like();
like6=()->{
System.out.println("i like lambda6");
};
like6.lamdba();
//7 简化lambda表达式
like6=()-> System.out.println("i like lambda7");
like6.lamdba();
//8 总结
/*lambda表达式在只有一行的情况下才能省略{};
前提必须是函数式接口;
多个参数也可以去掉(a ,b)->{};*/
}
}
//1 定义一个函数式接口
interface ILike {
void lamdba();
}
//2 实现类
class Like implements ILike {
@Override
public void lamdba() {
System.out.println("i like lambda");
}
}
线程的五大状态
创建:Thread t = new Thread;线程对象一旦创建就进入新生状态;
就绪:当调用start方法,线程就会立即进入就绪状态,但不意味着调度执行;
运行状态:进入运行状态,线程才真正执行线程体的代码块;
阻塞:当调用sleep,wait或同步锁时,线程进入阻塞状态,代码不在往下执行,阻塞事件解除后,重信进入就绪状态,等待cpu调度执行;
死亡:线程中断或者结束,就会进入死亡状态,不能重新启动;
测试停止线程:
//测试stop
//建议线程正常停止--->利用次数不建议死循环;
//建议使用标志位---->设置一个标志位;
//不要使用stop或者destory等过时或者jdk不建议使用的方法;
public class TestStop implements Runnable {
//设置一个标识位
private boolean flag=true;
@Override
public void run() {
int i=0;
while (flag){
System.out.println("线程正在执行");
}
}
public void stop(){
this.flag=false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 100; i++) {
System.out.println("i的值是--->"+ i);
if (i==1){
testStop.stop();
System.out.println("线程已停止");
}
}
}
}
sleep线程休眠:
1:指定当前线程阻塞的毫秒数;
2:sleep时间到达后线程进入就绪状态;
3:每个对象都有一把锁,sleep不会释放锁;
//模拟倒计时
public class TestSleep implements Runnable {
@Override
public void run() {
int num=10;
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num--);
if (num<=0){
break;
}
}
}
public static void main(String[] args) {
TestSleep testSleep=new TestSleep();
new Thread(testSleep).start();
}
}
线程礼让:
1:让当前执行的线程暂停,但不阻塞;
2:将线程从就绪状态变为就绪;
3:礼让不一定成功;
public class TestYield {
public static void main(String[] args) {
Yield yield=new Yield();
new Thread(yield,"a").start();
new Thread(yield,"b").start();
}
}
class Yield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"结束执行");
}
}
线程强制执行join:
join合并线程,待此线程执行完毕后,再执行其他线程;
//测试join方法
public class TestJoin {
public static void main(String[] args) throws InterruptedException {
JoinTest joinTest=new JoinTest();
Thread thread=new Thread(joinTest);
thread.start();
for (int i = 0; i < 100; i++) {
if (i==20){
System.out.println("i的值是---->"+i);
thread.join();
}
}
}
}
class JoinTest implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程vip来了------->");
}
}
}
线程状态观测(Thread.State)
NEW:尚未启动的线程处于此状态;
Runnable:在java虚拟机中执行的线程处于此状态;
Blocked:被阻塞等待监视器锁定的线程处于此状态;
WAITTING:正在等待另一个线程执行特定动作的线程处于此状态;
TIMED_WAITTING:正在等待另一个线程执行动作达到指定等待时间的线程处于此状态;
TERMINATED:已退出的线程处于此状态;
线程优先级:
Java提供一个线程调度器来监控程序启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行;
线程的优先级用数字来表示,范围1-10;
Thread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
使用以下方法改变或者获取优先级;getPriority().setPriority(int xxx);
守护线程
线程分为用户线程和守护线程,虚拟机需要确保用户线程执行完毕,虚拟机不需要等待守护线程执行完毕;
//测试守护线程和用户线程
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
Thread thread = new Thread(god);
thread.setDaemon(true);//设置为守护线程
thread.start();
You you = new You();
new Thread(you).start();//默认是用户线程
}
}
class God implements Runnable {
@Override
public void run() {
while(true){
System.out.println("上帝守护着你");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你开心的活着");
}
System.out.println("==========goodbye world========");
}
}
线程同步
由于同一进程的多个线程共享同一块内存空间,在带来方便的同时,也带来了访问冲突的问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制Synchornized,当一个线程获得对象的排他锁,独占资源,其它线程必须等待,使用后释放锁即可,存在以下问题:
1:一个线程持有锁会导致其它所有需要锁的线程挂起;
2:在多线程竞争下,加锁,释放锁会导致较多的上下文切换和调度延时,引起性能问题;
3:如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题;
import java.util.ArrayList;
import java.util.List;
//线程不安全集合
public class UnSafeList {
public static void main(String[] args) throws InterruptedException {
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(3000);
System.out.println(list.size());
}
}
同步方法:
synchronized方法控制对对象的访问,每个对象都有一把锁,每个synchronize方法都必须获得该方法的锁才能够执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到方法返回才会释放锁,会面被阻塞的线程才能得到这个锁,继续执行;
import java.util.ArrayList;
import java.util.List;
//线程不安全集合
public class UnSafeList {
public static void main(String[] args) throws InterruptedException {
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
Thread.sleep(3000);
System.out.println(list.size());
}
}
锁的应该是变化的属性;
死锁
多个线程各自占有一些共享资源,并且互相等待其它线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情况;
public class DealLockTest {
public static void main(String[] args) {
MakeUp makeUp =new MakeUp(0,"小米");
makeUp.start();
MakeUp makeUp2 =new MakeUp(1,"华为");
makeUp2.start();
}
}
class LipStick{};
class Mirror{};
class MakeUp extends Thread{
static LipStick lipStick = new LipStick();
static Mirror mirror = new Mirror();
int choice;
String name;
@Override
public void run() {
try {
makeUp();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
MakeUp(int choice,String name){
this.choice=choice;
this.name=name;
}
private void makeUp() throws InterruptedException {
if (choice==0){
synchronized (lipStick){
System.out.println(Thread.currentThread().getName()+"拿到了口红");
Thread.sleep(1000);
synchronized (mirror){//拿镜子锁
System.out.println(Thread.currentThread().getName()+"拿到了镜子");
}
/* synchronized (mirror){//拿镜子锁
System.out.println(Thread.currentThread().getName()+"拿到了镜子");
}*/
}
}else {
synchronized (mirror){
System.out.println(Thread.currentThread().getName()+"拿到了镜子");
Thread.sleep(1000);
synchronized (lipStick){
System.out.println(Thread.currentThread().getName()+"拿到了口红");
}
}
/* synchronized (lipStick){
System.out.println(Thread.currentThread().getName()+"拿到了口红");
}*/
}
}
}
Lock锁(可重入锁)
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
public static void main(String[] args) {
Lock lock = new Lock();
new Thread(lock).start();
new Thread(lock).start();
new Thread(lock).start();
}
}
class Lock implements Runnable {
int ticketNums = 10;
private final 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(ticketNums--);
} else {
break;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
线程协作
wait:表示线程一直等待,直到其它线程通知,与sleep不同,会释放锁;
notify():唤醒一个处于等待状态的线程;
notifyAll():唤醒同一个对象所有调用wait方法的线程,优先级别高的线程优先调度;
管程法示例:
//测试管程法
public class TestPc {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
new Productor(synContainer).start();
new Consumer(synContainer).start();
}
}
//生产者
class Productor extends Thread {
SynContainer synContainer;
public Productor(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public synchronized void run() {
for (int i = 1; i < 101; i++) {
try {
synContainer.push(new Chicken(i));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
//消费者
class Consumer extends Thread {
SynContainer synContainer;
public Consumer(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public synchronized void run() {
for (int i = 1; i < 101; i++) {
try {
synContainer.pop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
//产品
class Chicken {
int id;
public Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer {
Chicken[] chickens = new Chicken[10];
private int count = 0;//计数器
//生产者放入产品
public synchronized void push(Chicken chicken) throws InterruptedException {
if (count == chickens.length) {
//货柜已经满了,通知消费者消费
System.out.println("货柜已满,请消费者消费");
this.wait();
} if (true){
chickens[count] = chicken;
System.out.println("货柜第" + count + "位置放入了一只鸡,请消费");
count++;
this.notifyAll();
}
}
public synchronized Chicken pop() throws InterruptedException {
if (count == 0) {
System.out.println("货柜里面没有鸡,消费者正在等待");
this.wait();
}
System.out.println("货柜第" + count + "位置的鸡被消费");
count--;
Chicken chicken = chickens[count];
//通知生产者生产鸡
this.notifyAll();
return chicken;
}
}
线程池
背景:经常创建和销毁,使用量特别大的资源,比如并发情况下的线程,对性能影响很大;
思路:可以创建好多个线程,放入线程池当中,使用时直接获取;
corePoolSize:核心线程池的大小;
maxmumPoolSize:最大线程数;
keepAliveTime:线程没有任务时最多保持多长时间后会终止;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestPool {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new MyThread());
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("测试线程");
}
}