目录
1.进程和线程
1.1.进程和线程的概念
进程:操作系统中一个程序的执行周期为一个进程。
线程:一个程序同时执行多个任务。每个任务就相当于一个线程。
二者之间的联系和区别:
联系:没有进程就没有线程,进程一旦终止,其他线程也不复存在。
区别:进程是资源分配最小单位,线程是程序执行的最小单位,本质区别在于,每个进程拥有自己的一整套变量,二线程是共享数据,共享变量使得线程之间的通信比进程之间的通信更有效更方便
在实际应用中,多线程是非常有用,例如,一个浏览器应用同时下载好多张图片,好多首音乐,一个web服务器同时需要处理多个高并发的请求,这些都是多线程的应用
高并发:访问的线程量非常非常高
高并发带来的问题:服务器内存不够用,无法处理新的请求
1.2线程的状态
2.Java多线程的实现
2.1.实现多线程的三种方式:
- 1.继承Thread类实现多线程,但是继承类有局限性,所以一般使用第二种
- 2.Runnable接口实现多线程,但是run方法是没有返回值的,很多时候需 要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。
- 3.Callable接口实现多线程
以Runnable接口为例:
class Demo implements Runnable{
public String name;
@Override
public void run() {
for (int i=1;i<=10;i++)
{
try {
Thread.sleep(1000);
}catch (Exception e)
{
e.printStackTrace();
}
System.out.println("当前线程: " +Thread.currentThread().getName() +" "+i);
}
}
}
public class MyRunnable {
public static void main(String[] args) {
Demo demo1=new Demo();
Thread my=new Thread(demo1,"张三");
Thread my1=new Thread(demo1,"张四");
Thread my2=new Thread(demo1,"张吴");
my.start();
my1.start();
my2.start();
}
}
注意:start方法是Thread类中的方法,实现了Runnable接口,虽然解决了单继 承局限问题,但是没有start()方法被继承了。此时就需要关注Thread类提供的构造方法。
public Thread(Runnable target)
所以是可以接受Runnable接口对象的。
Callable接口范例:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyThread implements Callable
{
private int ticket=10;
@Override
public Object call() throws Exception {
while(this.ticket>0)
{
System.out.println("剩余票数"+this.ticket);
this.ticket--;
}
return "票卖完啦";
}
}
public class MyCallable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread mc=new MyThread();
FutureTask<String> task = new FutureTask<String>(mc);
Thread thread = new Thread(task);
thread.start();
System.out.println(task.get());
}
}
结果:
2.2实现Runnable接口的俩种方式
对于Runnable接口对象可以采用匿名内部类和Lambda表达式来定义
匿名内部类:
import static java.lang.Thread.sleep;
public class testdemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i<=10; i++)
{
System.out.println("Hello");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}) .start();
}
}
Lambda表达式进行Runnable对象创建:
public class testdemo02 {
public static void main(String[] args) {
Runnable runnable=()-> System.out.println("hello");
new Thread(runnable).start();
}
}
总结:使用Runnable实现的多线程的程序类可以更好的描述出程序共享的概念
3.多线程的常用操作方法:
3.1线程命名与取得
3.2线程方法的介绍
1.线程休眠:sleep方法
线程休眠:指的是让线程暂缓执行一下,等到了预计时间之后再恢复执行。
2.线程让步yield()方法
线程让步:停当前正在执行的线程对象,并执行其他线程。
3.join()方法
等待线程终止:意思就是如果在主线程中调用该方法时就会让主线程休眠,让调用该方法的线程run方法先执行 完毕之后在开始执行主线程。
4.线程停止:
多线程停止的方式有三种
- 设置标记位,可以是线程正常退出。
- 使用stop方法强制使线程退出,但是该方法不太安全所以已经被废弃了。
- 使用Thread类中的一个interrupt() 可以中断线程。(interrupt() 方法只是改变中断状态而已,它不会中断一个正在运行的线程。这一方法实际完成的是,给受阻塞的线 程发出一个中断信号,这样受阻线程就得以退出阻塞的状态。)
5.线程设置优先级
在Thread类中提供有如下优先级方法:
设置优先级:
public final void setPriority(int newPriority)
取得优先级:
public final int getPriority()
对于优先级设置的内容可以通过Thread类的几个常量来决定
1. 最高优先级:public final static int MAX_PRIORITY = 10;
2. 中等优先级:public final static int NORM_PRIORITY = 5;
3. 最低优先级:public final static int MIN_PRIORITY = 1;
6.守护线程:
守护线程是一种特殊的线程,它属于是一种陪伴线程。简单点说 java 中有两种线程:用户线程和守护线程。可以通 过isDaemon()方法来区别它们:如果返回false,则说明该线程是“用户线程”;否则就是“守护线程”。典型的守护线 程就是垃圾回收线程。只要当前JVM进程中存在任何一个非守护线程没有结束,守护线程就在工作;只有当最后一 个非守护线程结束时,守护线程才会随着JVM一同停止工作。
注意:主线程main是用户线程