多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理” 。
继承Thread类重写run()方法
使用时调用start()方法
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 test=new TestThread1();
test.start();
for (int i = 0; i < 2000; i++) {
System.out.println("我在吃饭-------*"+i);
}
}
}
实现Runnable接口
实现run()方法
将实现的对象放入Thread中调用start()方法
推荐使用实现Runnable接口的方式实现多线程
//多个线程同时操作同一个对象
//火车票
public class TestThread4 implements Runnable {
private int a=10;
public void run() {
while (true){
if (a<=0){
break;
}
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+a--+"张票");
}
}
public static void main(String[] args) {
TestThread4 t=new TestThread4();
new Thread(t,"小明").start();
new Thread(t,"老师").start();
new Thread(t,"黄牛党").start();
}
}
实现多线程下载网络图片
导入依赖
org.apache.commons commons-io1.3.2
//练习多线程,实现多线程同步下载图片
public class TestThread2 implements Runnable{
private String url;
private String name;
public TestThread2(String url,String name){
this.url=url;
this.name=name;
}
public void run() {
WebDownloader downloader=new WebDownloader();
downloader.downloader(url,name);
System.out.println("下载文件:"+name);
}
public static void main(String[] args) {
//如果file不加路径会默认在当前项目中创建
TestThread2 t1=new TestThread2("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","1.jpg");
TestThread2 t2=new TestThread2("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","2.jpg");
TestThread2 t3=new TestThread2("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","3.jpg");
new Thread(t1).start();
new Thread(t2).start();
new Thread(t3).start();
}
}
//下载器
class WebDownloader{
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("io异常downloader方法出现问题");
}
}
}
注意:当多个线程操作同一个资源的时候会出现问题
龟兔赛跑public class Race implements Runnable {
private static String winner;
public void run() {
for (int i = 1; i <= 100; i++) {
boolean flag = gemeOver(i);
//模拟兔子睡觉
if ("兔子".equals(Thread.currentThread().getName()) && i%50==0){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//出现胜利者结束比赛
if (flag){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
public boolean gemeOver(int i){
if (winner!=null){
return true;
}else if (i>=100){
winner=Thread.currentThread().getName();
System.out.println("winner is"+winner);
return true;
}
return false;
}
public static void main(String[] args) {
Race race=new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
实现Callable接口
public class TestCallable implements Callable{ private String url; private String name; public TestCallable(String url,String name){ this.url=url; this.name=name; } public Boolean call() { WebDownloader downloader=new WebDownloader(); downloader.downloader(url,name); System.out.println("下载文件:"+name); return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { //如果file不加路径会默认在当前项目中创建 TestCallable t1=new TestCallable("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","1.jpg"); TestCallable t2=new TestCallable("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","2.jpg"); TestCallable t3=new TestCallable("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","3.jpg"); //创建执行服务 ExecutorService ser= Executors.newFixedThreadPool(3); //提交执行 Future r1=ser.submit(t1); Future r2=ser.submit(t2); Future r3=ser.submit(t3); //获取结果 Boolean b1=r1.get(); Boolean b2=r2.get(); Boolean b3=r3.get(); System.out.println(b1); System.out.println(b2); System.out.println(b3); //关闭服务 ser.shutdownNow(); } } //下载器 class WebDownloader{ public void downloader(String url,String name) { try { FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("io异常downloader方法出现问题"); } } }
- 实现 Callable接口
- 实现call()方法,该方法有返回值
- 创建执行服务 ExecutorService ser= Executors.newFixedThreadPool(3);
- 提交执行 Future r1=ser.submit(t1);
- 获取结果 Boolean b1=r1.get();
- 关闭服务 ser.shutdownNow();
其中Boolean是call()方法的返回值
静态代理模式public class StaticProxy {
public static void main(String[] args) {
new MarryProxy(new You()).HappyMarry();
}
}
interface Marry{
public void HappyMarry();
}
class You implements Marry{
public void HappyMarry() {
System.out.println("今天结婚了很开心!");
}
}
class MarryProxy implements Marry{
private Marry marry;
public MarryProxy(Marry marry){
this.marry=marry;
}
public void HappyMarry() {
on();
marry.HappyMarry();
to();
}
public void on(){
System.out.println("结婚前,布置现场");
}
public void to(){
System.out.println("结婚后,整理现场");
}
}
静态代理总结
真实对象和代理对象都要实现同一接口
代理对象要代理真实角色
优点
代理对象可以帮助真实角色做其他的事
真实角色可以更加专注的做自己的事
Lambda表达式
函数式接口:只有一个方法接口的接口为函数式接口
lambda表达式的简化过程
public class TestLambda1 {
//3.静态内部类
static class Like2 implements ILike{
public void lambda() {
System.out.println("I like lambda2");
}
}
public static void main(String[] args) {
ILike like=new Like();
like.lambda();
like=new Like2();
like.lambda();
//4.局部内部类
class Like3 implements ILike{
public void lambda() {
System.out.println("I like lambda3");
}
}
like=new Like3();
like.lambda();
//5.匿名内部类
like=new ILike() {
public void lambda() {
System.out.println("I like lambda4");
}
};
like.lambda();
//6.lambda表达式
like=()->{
System.out.println("I like lambda5");
};
like.lambda();
}
}
//1.定义接口
interface ILike{
void lambda();
}
//2.创建实现类
class Like implements ILike{
public void lambda() {
System.out.println("I like lambda");
}
}
public class TestLambda2 {
public static void main(String[] args) {
Love love=null;
//匿名内部类
love=new Love() {
@Override
public void love(int a) {
System.out.println("I love you "+a);
}
};
love.love(520);
//lambda表达式
love=(int a)->{
System.out.println("I love you "+a);
};
love.love(521);
//简化返回值类型
love=(a)->{
System.out.println("I love you "+a);
};
love.love(522);
//简化小括号
love=a->{
System.out.println("I love you "+a);
};
love.love(523);
//简化大括号
love=a->System.out.println("I love you "+a);
love.love(524);
}
}
interface Love{
void love(int a);
}
总结:
- lambda表达式只有在一行代码的时候才能省略大括号,不然需要用大括号包括起来
- lambda必须是函数式接口
- 多个参数也可以去点参数类型,但是必须都去掉
- 方法参数是一个的话不需要家小括号,超过一个则需要加
- 建议线程自己停止--->利用次数,不建议死循环
- 建议使用标志位停止线程-->设置一个标志位
- 建议不要使用stop,destroy等过时或者JDK不建议使用的方法
public class TestStop implements Runnable {
private boolean falg=true;
public void run() {
int i=0;
while(falg){
System.out.println("run...Threda:"+i++);
}
}
public void stop(){
this.falg=false;
}
public static void main(String[] args) {
TestStop t=new TestStop();
new Thread(t).start();
for (int i = 0; i < 1000; i++) {
System.out.println("i="+i);
if (i==900){
t.stop();
System.out.println("线程停止了");
}
}
}
}
线程休眠Sleep
- sleep(时间)指定当前线程阻塞的毫秒数
- sleep存在异常
- sleep时间到达后,线程进入就绪状态
- sleep可以模拟网络延时,倒计时等
- 每一个对象都有一个锁,sleep不会释放锁
模拟网络延时:放大问题的发生性
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestSleep2 {
//模拟倒计时
public static void tenDown() throws InterruptedException {
int n=10;
while (true){
Thread.sleep(1000);
System.out.println(n--);
if (n<=0){
break;
}
}
}
//打印当前系统时间
public static void dataShow(){
Date date=new Date();
while (true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
date=new Date();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
try {
TestSleep2.tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
TestSleep2.dataShow();
}
}
线程礼让 yield
- 礼让线程,让当前正在执行的线程暂停,但不阻塞
- 将线程从就运行态转为就绪状态
- 让cpu调度礼让不一定会成功,kancpu心情
public class TestYield {
public static void main(String[] args) {
MyYield myYield=new MyYield();
new Thread(myYield,"A").start();
new Thread(myYield,"B").start();
}
}
class MyYield implements Runnable{
public void run() {
System.out.println(Thread.currentThread().getName()+"-->线程开始");
Thread.yield();//礼让
System.out.println(Thread.currentThread().getName()+"-->线程结束");
}
}
线程强制执行 join
此线程执行完后在执行其他线程
理解为插队
public class TestJoin implements Runnable {
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("线程vip在执行:"+i);
}
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin=new TestJoin();
Thread t=new Thread(testJoin);
t.start();
for (int i = 0; i < 500; i++) {
if (i==200){
t.join();//线程插队,让cpu先执行他
}
System.out.println("main执行:"+i);
}
}
}
观测线程状态
public class TestState {
public static void main(String[] args) {
Thread thread=new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("==========");
});
//观察状态
Thread.State state = thread.getState();
System.out.println(state);//new
//观察启动后
thread.start();//启动线程
state = thread.getState();
System.out.println(state);//run
while (state!=Thread.State.TERMINATED){//只要线程不终止就一直输出
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
state=thread.getState();
System.out.println(state);
}
}
}
线程优先级
- 先设置优先级在使用
- 执行顺序不一定是优先级高的先执行,但是概率会更大
class MyPriority implements Runnable{
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MyPriority myPriority=new MyPriority();
Thread t1=new Thread(myPriority);
Thread t2=new Thread(myPriority);
Thread t3=new Thread(myPriority);
Thread t4=new Thread(myPriority);
Thread t5=new Thread(myPriority);
Thread t6=new Thread(myPriority);
t1.start();
t2.setPriority(1);//设置优先级
t2.start();
t3.setPriority(7);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
t5.setPriority(Thread.MIN_PRIORITY);
t5.start();
t6.setPriority(3);
t6.start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());//获取优先级
}
}
守护线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如,后台记录日志,监控内存,垃圾回收等待。
也就是说守护线程在用户线程结束后也会继续执行 ,直到程序结束虚拟机关闭才会结束。
public class TestDaemo {
public static void main(String[] args) {
God god=new God();
You you=new You();
Thread thread=new Thread(god);
thread.setDaemon(true);//变成守护线程,该方法默认是false
thread.start();
//上帝插队的话就会无线循环
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!====");
}
}
线程同步机制
由于一个进程多个线程访问同一块存储区域,带来方便的同时也带来了问题, 为了保证访问的正确性,因此引入了锁机制 synchronized,当一个线程获取 对象的排他锁后,其他线程必须等待,使用后释放锁即可,存在以下问题:
- 一个线程持有锁,会导致其他需要此锁的线程挂起
- 在多线竞争下,加锁,释放锁会导致上下文切换 和 调度延时,引起性能问题
- 如果一个优先级高的线程等待一个优先级低的线程,会导致优先级倒置,
- 引起性能问题
努力学习更新中~



