**一.
1.程序 进程 线程**
程序:
- 程序是指令和数据的一个有序集合,其本身没有任何运行的含义,是一个静态的概念。
进程:
- 进程是程序执行的一个过程,它是一个动态的概念,是系统资源分配的单位。例如:我们的播放器,游戏等等
线程:
- 线程是CPU调度和执行的单位,例如:我们程序中的main()被称为主线程,为系统的入口,用于执行整个程序。
小结:
- 一个进程至少包括一个线程,不然就没有存在的意义。
在程序运行时,即使没有创建自己的线程,后台仍然还会有很多线程,例如:main()线程,gc线程等等 - 在一个进程中,如果开辟了多个线程,那这些线程的运行由调度器安排调度,先后顺序不能认为干预。
- 对同一份资源的操作时,会存在资源抢夺的问题,这个时候就要加入并发控制。例如有100张电影票,但是同时有10000个人来抢,如果不加入并发控制,这个时候票的余额就会出现-9900。
2.如何创建一个进程
1. 继承Thread类
2. 继承Thread类
3. 重写run()方法
4. 通过< 子类对象.start()>启动这个线程
实例:
package java_demo.多线程;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//通过多线程下载网络图片
public class Thread_download extends Thread{
private String name;
private String url;
public Thread_download(String name, String url) {
this.name = name;
this.url = url;
}
public void run()
{
Download download = new Download();
download.download(url,name);
System.out.println("已经下载图片到"+name);
}
public static void main(String[] args) {
Thread_download test1 = new Thread_download("test1", "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=24336452,906724543&fm=26&gp=0.jpg");
Thread_download test2 = new Thread_download("test2", "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3649178992,1821853682&fm=26&gp=0.jpg");
Thread_download test3 = new Thread_download("test3", "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3401732207,3726302783&fm=26&gp=0.jpg");
test1.start();
test2.start();
test3.start();
}
}
class Download{
public void download(String url,String name)
{
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("下载器异常!!!");
}
}
}
1. 实现Runnable接口
2. 实现Runnable接口
3. 定义无参run()方法
4. 通过<传入目标对象+Thread对象.start()>启动这个线程
实例:
package java_demo.多线程;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class Runnable_download implements Runnable{
private String name;
private String url;
public Runnable_download(String name, String url) {
this.name = name;
this.url = url;
}
@Override
public void run() {
Download download = new Download();
download.download(url,name);
System.out.println("已经下载图片到"+name);
}
public static void main(String[] args) {
Runnable_download test1 = new Runnable_download("test1", "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=24336452,906724543&fm=26&gp=0.jpg");
Runnable_download test2 = new Runnable_download("test2", "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3649178992,1821853682&fm=26&gp=0.jpg");
Runnable_download test3 = new Runnable_download("test3", "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3401732207,3726302783&fm=26&gp=0.jpg");
new Thread(test1).start();
new Thread(test2).start();
new Thread(test3).start();
}
}
class Downloads{
public void download(String url,String name)
{
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("下载器异常!!!");
}
}
}
小结
- 建议使用Runnable接口,因为其避免了单继承的局限性,灵活方便,方便一个对象被多个线程使用。
3.lambda表达式
优点
- 避免内部匿名类定义过多。
- 去掉了一些没有意义的代码,只留下了核心逻辑。
语法格式
- 语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 ,读作(goes to)。
4.静态代理模式
总结
- 真实的角色 代理角色(需要真实角色的引用)
- 共同实现一个接口
实例
package java_demo.多线程;
//静态代理模式
/*
1.真实的角色
2.代理角色
3.共同实现的接口
*/
public class Thread_proxy {
public static void main(String[] args) {
Weeding weeding = new Weeding(new You());
weeding.Happymarry();
}
}
interface Marry
{
void Happymarry();
}
class You implements Marry
{
@Override
public void Happymarry() {
System.out.println("我要结婚了,超级开心!!!");
}
}
class Weeding implements Marry
{
private Marry marry;
public Weeding(Marry marry) {
this.marry = marry;
}
@Override
public void Happymarry() {
before();
this.marry.Happymarry();
after();
}
public void before()
{
System.out.println("结婚之前布置现场!!");
}
public void after()
{
System.out.println("结婚之后数钱!!!");
}
}
5.线程的生命周期
- 初始状态:线程对象一旦创建,就进入了初始状态。
- 就绪状态:当调用start()方法时,线程就进入了就绪状态,但不代表立即调度执行想,需要CPU对你进行调度你才是运行状态,否则一直就是就绪状态。
- 运行状态:被调度程序选择作为当前线程时的状态。
- 阻塞状态:当调用sleep,wait或者同步锁时,线程进入阻塞状态,程序不往下继续执行,阻塞事件解除以后,线程重新进入就绪状态,等待调度程序调度。
- 死亡状态:线程中断或者结束。一旦进入死亡状态,就不能再次启动。
6.线程的停止
- 建议使用正常停止——————>利用次数
- 建议使用标志位
- 不建议使用stop,destroy等jdk不建议使用的过时方法
实例
package java_demo.多线程;
/*
线程停止
1.建议线程正常停止——————>利用次数
2.建议使用标志位
3.不建议使用stop或destroy等过时且jdk不建议使用的方法
*/
public class Thread_stop implements Runnable{
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag)
{
System.out.println("runTread"+i++);
}
}
public void stop()
{
this.flag = false;
}
public static void main(String[] args) {
Thread_stop thread_stop = new Thread_stop();
new Thread(thread_stop).start();
for (int i = 0; i < 200; i++) {
System.out.println("mainThread"+i);
if (i==100)
{
thread_stop.stop();
System.out.println("run线程已经停止!!!");
}
}
}
}
7.线程休眠
- 利用sleep方法让线程休眠,进入阻塞状态
实例:
package java_demo.多线程;
/*
模拟倒计时
*/
public class Thread_sleep {
public static void main(String[] args) {
sleep();
}
public static void sleep()
{
int num = 10;
while (true)
{
System.out.println("倒计时:"+num--);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (num<=0)
{
break;
}
}
}
}
8.线程礼让
- 利用yield()方法 让当前线程暂停,但是不进入阻塞状态
- 让线程重新回到就绪状态,等待调度程序对其进行调度
- 最终CPU调度全靠心情,所以礼让不一定成功。
实例:
package java_demo.多线程;
public class Thread_yield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"A").start();
new Thread(myYield,"B").start();
}
}
class MyYield implements Runnable
{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行!!");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程结束执行!!");
}
}
9.线程强制执行(插队)
join合并线程,待此线程结束以后再执行其他线程,其他线程阻塞。
实例
package java_demo.多线程;
public class Thread_join implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("我是vip线程!!我正在执行第"+i);
}
}
public static void main(String[] args) {
Thread_join thread_join = new Thread_join();
Thread thread = new Thread(thread_join);
thread.start();
for (int i = 0; i < 500; i++) {
System.out.println("我是主线程,我正在执行!!第"+i);
if (i == 200)
{
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
10.线程的优先级
-
设置线程优先级
对象.setpriority(int n) (0<=n<=10)
-
获取线程优先级
对象.getpriority(int n)
*线程优先级高并不一定代表先调度,只是说概率提高了。
实例
package java_demo.多线程;
public class Thread_priority {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"————————>"+Thread.currentThread().getPriority());
Mypriority mypriority = new Mypriority();
Thread thread1 = new Thread(mypriority,"a");
Thread thread2 = new Thread(mypriority,"b");
Thread thread3 = new Thread(mypriority,"c");
Thread thread4 = new Thread(mypriority,"d");
Thread thread5 = new Thread(mypriority,"e");
thread1.start();
thread2.setPriority(3);
thread2.start();
thread3.setPriority(5);
thread3.start();
thread4.setPriority(7);
thread4.start();
thread5.setPriority(10);
thread5.start();
}
}
class Mypriority implements Runnable
{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"————————>"+Thread.currentThread().getPriority());
}
}
11.守护线程(Deamon)
- 线程分为守护线程和用户线程
- 虚拟机必须保证用户线程执行完毕
- 虚拟机不必等待保护线程执行完毕
- 保护线程有垃圾回收,监控内存等等机制
实例
package java_demo.多线程;
/*
守护线程
*/
public class Thread_deamon {
public static void main(String[] args) {
Gad gad = new Gad();
Me me = new Me();
Thread thread = new Thread(gad);
thread.setDaemon(true);//false代表用户线程
thread.start();
new Thread(me).start();
}
}
class Gad implements Runnable
{
@Override
public void run() {
while (true)
{
System.out.println("上帝守护着你!!");
}
}
}
class Me implements Runnable
{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("开开心心活着第"+i+"年!");
}
System.out.println("goodbye world!!!!!!");
}
}
12.线程同步
- 并发:同一个对象被多个线程操作时,别叫做并发。
- 线程同步:线程同步其实就是一种等待机制,当多个线程想要他是去操作一个对象时,它们就会进入到这个对象的等待池中形成一个队列,等上一个线程使用结束,下一个线程再使用。
什么时候用:处理多线程问题时,当多个线程访问一个对象时,并且有的对象还想修改这个对象,这个时候我们就需要线程同步。 - 线程同步形成条件:队列+锁
*通俗一点来讲,线程同步就像很多人排队去用一个厕所,前面的人进去以后把锁锁上,结束以后把锁打开,下一个进去把锁锁上…
优点:确保了数据在方法中被访问的正确性,安全性。
缺点:降低效率,一个线程持有锁会导致其他需要此锁的线程挂起。(鱼跟熊掌不可兼得)
13.线程池
背景
- 经常创建和销毁使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
思路
- 可以提前创建好多个线程放入线程池中,使用时直接取,使用完放入线程池,这样就避免了重复的创建和销毁,实现了重复利用。
优点
- 提高了响应速度,减少了创建线程的时间。
- 降低了资源的消耗。
- 便于线程管理。
实例:
package java_demo.多线程;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Thread_pool {
public static void main(String[] args) {
//创建线程池
ExecutorService server = Executors.newFixedThreadPool(10);
Pool pool = new Pool();
server.execute(pool);
server.execute(pool);
server.execute(pool);
server.execute(pool);
server.execute(pool);
//关闭连接
server.shutdown();
}
}
class Pool implements Runnable
{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}