1.进程与线程
1.1进程与线程的概念
进程概念:操作系统中一个程序的执行周期(例如:打开qq然后关闭qq这就是一个进程)
进程是操作系统中资源分配的最小单位
线程概念:进程中的一个任务
线程是操作系统中资源调度的最小单位
进程与线程的区别:
- 地址空间:同一进程中的线程共享本进程的地址空间,而进程之间是独立的地址空间
- 资源内存:同一进程中的线程共享本进程的资源,内存(堆内存和方法区内存,栈内存不共享),而进程的资源是彼此独立的
- 两者均可并发执行(多个任务轮流切换执行)
1.2线程状态
创建,就绪,运行,阻塞,终止
2.多线程实现
2.1继承Thread类(实现了Runnable接口)
示例:
class MThread extends Thread{
private String cat;
public MThread(String cat){
this.cat = cat;
}
public void run(){
for(int i = 0; i < 5;i++){
System.out.println(this.cat+"喜欢"+i);
}
}
}
public class MyThread {
public static void main(String[] args) {
Thread thread1 = new MThread("小花");
Thread thread2 = new MThread("小白");
Thread thread3 = new MThread("桔子");
thread1.start();
thread2.start();
thread3.start();
}
}
为什么调用start()方法而不是run()方法?
- run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面。
- 调用start()方法,会自动调用线程的run()方法
- start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码:
- 调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法。
- run()方法只是类的一个普通方法,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
2.1实现Runnable接口
示例1:
class MThread implements Runnable{
private String cat;
public MThread(String cat){
this.cat = cat;
}
public void run(){
for(int i = 0; i < 5;i++){
System.out.println(this.cat+"喜欢"+i);
}
}
}
public class MyThread {
public static void main(String[] args) {
Mthread thread1 = new MThread("小花");
Mthread thread2 = new MThread("小白");
Mthread thread3 = new MThread("桔子");
new Thread(thread1).start();
new Thread(thread2).start();
new Thread(thread3).start();
}
}
示例二:利用匿名内部类
public class MyThread {
public static void main(String[] args) {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("小花最调皮");
}
}).start();
}
}
示例三:利用Lamdba表达式
public class MyThread {
public static void main(String[] args) {
Runnable runnable = ()-> System.out.println("小花最调皮");
new Thread(runnable).start();
}
}
Thread与Runnable的区别(Runnable优势)
- 实现Runnable接口更容易实现资源的共享
- 避免了单继承的局限性
- 线程池只能放入实现Runnable,Callable接口的类,而不能直接放入继承Thread的类
2.3实现Callable接口
class Mthread implements Callable{
private int cat = 4;
@Override
public Object call() throws Exception {
while(cat > 0){
System.out.println("还有"+cat+"只猫");
cat--;
}
return "猫咪回家了,撸猫明请早";
}
}
public class MyThread {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> callable = new FutureTask<>(new Mthread());
new Thread(callable).start();
System.out.println(callable.get());
}
}
Runnable中的run()方法没有返回值,但是很多时候需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。
3.多线程的常用操作方法
3.1线程的命名和取得
如果没有设置线程名称,则会自动分配一个线程名称
- public final synchronized void setName(String name);//创建线程的时候设置名称
- public Thread(Runnable target,String name);//设置线程名称
- public final String getName();//获得线程名称
public class MyThread{
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
//设置线程名称
this.setName("小白");
System.out.println(this.getName());
}
}.start();
//通过构造方法设置名称
new Thread("小花"){
public void run(){
System.out.println(this.getName());
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
//获得当前线程名称
System.out.println(Thread.currentThread().getName());
}
}).start();
}
}
3.2线程休眠(sleep方法)
sleep():让线程暂缓一下,到了预定的时间后再继续执行。在此期间,会交出CPU的使用权,但是不会释放锁。也就是说,若当前线程持有某个对象的锁,那么sleep后,其他的线程无法访问此对象。并且调用此方法后,线程回到阻塞态。
- public static native void sleep(long millis) throws InterruptedException
class MThread implements Runnable {
private String cat;
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "喜欢" + i);
}
}
}
3.3 线程让步(yield方法)
yield():暂停当前线程的执行,转而执行其他线程。会交出CPU的使用权,但是不能控制具体的交出时间。并且调用此方法不会释放锁。并且调用此方法后,线程回到就绪态。
class MThread implements Runnable {
private String cat;
public void run() {
for (int i = 0; i < 5; i++) {
Thread.yield();
System.out.println(Thread.currentThread().getName() + "喜欢" + i);
}
}
}
3.4join()方法
join():等待该线程终止。也就说必须等该线程执行完之后,才能执行要执行的线程。
public class MyThread{
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0;i < 5;i++){
System.out.println(Thread.currentThread().getName());
}
}
});
Thread thread2 = new Thread(){
@Override
public void run() {
for (int i = 0;i < 5;i++){
try {
thread1.join();
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread1.start();
thread2.start();
}
}
3.5线程停止
- 设置标记位,可以是线程正常退出。
class MThread implements Runnable {
private boolean flag = true;
@Override
public void run() {
int i = 1;
while (flag) {
try {
Thread.sleep(1000);
System.out.println("第"+i+"次执行,线程名称为"+Thread.currentThread().getName());
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
public class MyThread{
public static void main(String[] args) throws InterruptedException {
MThread myThread = new MThread();
new Thread(myThread).start();
Thread.sleep(4500);
myThread.setFlag(false);
}
}
- 使用stop方法强制使线程退出(弃用)
stop方法会解除线程获得的所有锁定,当调用stop方法时,这个线程对象正在运行的线程会立即停止,因此可能会产生不完整的残废数据。
- 使用Thread类中的一个 interrupt() 可以中断线程。
interrupt() 方法只是改变中断状态而已,它不会中断一个正在运行的线程。
class MThread implements Runnable {
@Override
public void run() {
boolean bool = Thread.currentThread().isInterrupted();
while (!bool){
try {
Thread.sleep(1000);
System.out.println("阻塞情况下"+bool);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.6线程优先级
- 最高优先级:public final static int MAX_PRIORITY = 10;
- 中等优先级:public final static int NORM_PRIORITY = 5;
- 最低优先级:public final static int MIN_PRIORITY = 1;
- 设置优先级:public final void setPriority(int newPriority)
- 获得优先级:public final int getPriority()
class MThread implements Runnable {
@Override
public void run(){
System.out.println(Thread.currentThread().getPriority());
}
}
public class MyThread{
public static void main(String[] args) throws InterruptedException {
MThread mt = new MThread();
Thread t1 = new Thread(mt,"1") ;
Thread t2 = new Thread(mt,"2") ;
Thread t3 = new Thread(mt,"3") ;
t1.setPriority(6);
t2.setPriority(Thread.MIN_PRIORITY);
t3.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
t3.start();
}
3.7守护线程
java中有两种线程:用户线程和守护线程
典型的守护线程为垃圾回收线程,只要当前JVM进程中存在任何一个非守护进程还没有结束,那么守护进程就要一直工作。只有当最后一个非守护线程执行完后,守护线程才会关闭
可以用isDaemon()方法进行区别
class MThread implements Runnable {
@Override
public void run(){
System.out.println(Thread.currentThread().isDaemon());
}
}