Java多线程深入理解学习笔记之二-----多线程实现方案1及方法简介

多线程的实现方案1:

继承Thread类

重写run()方法

在测试类中使用start()方法

贴一下代码(自定义线程):

package textDemo;

public class MyThread extends Thread{
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName()+":"+i);
		}
	}
}

测试类中的代码:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
        MyThread myThread = new MyThread();
		MyThread myThread2 = new MyThread();
        myThread.start();
        myThread2.start();
}

几个小问题:

为什么要重写run()方法?

启动线程使用的是那个方法?

线程能不能多次启动?

run()start()方法的区别?

1.为什么要重写run()方法?

因为不是该类中的所有代码都被线程所执行的,Java中Thread类中提供了run()用来包含那些被执行的代码

2.start()方法与run()方法的区别?

注:start()方法是先启动该线程,然后再通过JVM虚拟机调用其中的run()方法

        而如果直接使用run()方法就是直接调用,相当于看到了单线程的使用

3.线程能不能多次启动

同一个线程不能执行两次start()方法,为什么呢?

因为前面已经说了,在调用start()方法相当于启动该线程,而你第二次去调用start()方法时该线程已经启动了,你不能再启动一次吧,所以会抛出非法的线程状态异常

如何获取和设置线程名称

Thread类的基本获取和设置方法

public final String getName()

public final void setName(String name)

其实通过构造方法也可以给线程起名字

下面是具体的代码实现:

自定义线程类:

package textDemo;

public class MyThread extends Thread{
	public  MyThread() {
		
	}
	
	public MyThread(String name) {
		super(name);
	}
	
	
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName()+":"+i);
		}
	}
}

 测试类代码:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread myThread2 = new MyThread();
		//设置线程的名字
		myThread.setName("李渊");
		myThread2.setName("李世明");
		myThread.start();
		myThread2.start();
	}
}

思考:

如何获取main方法所在的线程名称以及没有继承Thread的子类的线程名称呢?

public static Thread currentThread()

这样就可以获取任意方法所在的线程名称,代码如下

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
//		MyThread myThread = new MyThread();
//		MyThread myThread2 = new MyThread();
//		//设置线程的名字
//		myThread.setName("李渊");
//		myThread2.setName("李世明");
//		myThread.start();
//		myThread2.start();
		System.out.println(Thread.currentThread().getName());
	}
}

Console显示效果:

线程调度

假如我们的计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到 CPU时间片,也就是使用权,才可以执行指令。那么Java是如何对线程进行调用的呢?

l线程有两种调度模型:

分时调度模型   所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片

抢占式调度模型   优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些。

Java使用的是抢占式调度模型。

Java如何设置和获取线程优先级

public final int getPriority()

public final void setPriority(int newPriority)

注:public final void setPriority(int newPriority)方法中的参数newPriority应该在MIN_PRIORITY与MAX_PRIORITY之间, 不然会抛出异常

MIN_PRIORITY = 1;(最小优先级)

NORM_PRIORITY=5;(默认优先级)

MAX_PRIORITY = 10;(最大优先级)

但是比如说你给一个线程A设置优先级为10,另外一个线程B的优先级设置为1会怎样呢?

会先执行完线程A再执行线程B嘛?我们说线程的执行是有随机性的,即使设置了线程的优先级,执行的几率只能说大一点,不会说执行完线程A再去执行线程B

下面我们来用代码来验证一下:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread myThread2 = new MyThread();
		MyThread myThread3 = new MyThread();
		//设置线程的名字
		myThread.setName("李渊");
		myThread2.setName("李世明");
		myThread3.setName("李XX");
		//设置线程的优先级
		myThread.setPriority(10);
		myThread3.setPriority(1);
		
		myThread.start();
		myThread2.start();
		myThread3.start();
//		System.out.println(Thread.currentThread().getName());
	}
}

结果如下:

李世明:0
李XX:0
李渊:0
李XX:1
李世明:1
李XX:2
李XX:3
李渊:1
李XX:4
李世明:2
李XX:5
李渊:2
李渊:3
李渊:4
李渊:5
李渊:6
李渊:7
李渊:8
李渊:9
李XX:6
李XX:7
李XX:8
李XX:9
李世明:3
李世明:4
李世明:5
李世明:6
李世明:7
李世明:8
李世明:9

所以说设置了线程的优先级只能说优先执行的几率大而已

线程控制

我们已经知道了线程的调度,接下来我们就可以使用如下方法对象线程进行控制

线程休眠

public static void sleep(long millis)

线程加入

public final void join()

线程礼让

public static void yield()

后台线程

public final void setDaemon(boolean on)

中断线程

public final void stop()

public void interrupt()

线程休眠

贴个文档再贴代码吧,好理解

下面是代码:

package textDemo;

import java.util.Date;

public class MyThread extends Thread{
	public  MyThread() {
		
	}
	
	public MyThread(String name) {
		super(name);
	}
	
	
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(getName()+":"+i+" Time: "+new Date().toLocaleString());
			try {
				//设置当前线程休眠一秒钟
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

 测试类的代码:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread myThread2 = new MyThread();
//		MyThread myThread3 = new MyThread();
		//设置线程的名字
		myThread.setName("李渊");
		myThread2.setName("李世明");
		//设置线程的优先级
//		myThread.setPriority(10);
//		myThread3.setPriority(1);
		
		myThread.start();
		myThread2.start();
//		myThread3.start();
//		System.out.println(Thread.currentThread().getName());
	}
}

显示效果:

线程加入

public final void join()

同样先贴文档,再贴代码:

自定义线程中的代码:

package textDemo;

import java.util.Date;

public class MyThread extends Thread{
	public  MyThread() {
		
	}
	
	public MyThread(String name) {
		super(name);
	}
	
	
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(getName()+":"+i);
//			try {
//				//设置当前线程休眠一秒钟
//				Thread.sleep(1000);
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
		}
	}
}

测试类中的代码:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread myThread2 = new MyThread();
//		MyThread myThread3 = new MyThread();
		//设置线程的名字
		myThread.setName("李渊");
		myThread2.setName("李世明");
		//设置线程的优先级
//		myThread.setPriority(10);
//		myThread3.setPriority(1);
		myThread.start();
		try {
			myThread.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		myThread2.start();
//		myThread3.start();
//		System.out.println(Thread.currentThread().getName());
	}
}

运行效果(调用join()方法后):

线程礼让

public static void yield()

先上文档,再上代码:

自定义线程类中的代码:

package textDemo;

import java.util.Date;

public class MyThread extends Thread{
	public  MyThread() {
		
	}
	
	public MyThread(String name) {
		super(name);
	}
	
	
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(getName()+":"+i);
			Thread.yield();
//			try {
//				//设置当前线程休眠一秒钟
//				Thread.sleep(1000);
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
		}
	}
}

测试类中的代码:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread myThread2 = new MyThread();
//		MyThread myThread3 = new MyThread();
		//设置线程的名字
		myThread.setName("李渊");
		myThread2.setName("李世明");
		//设置线程的优先级
//		myThread.setPriority(10);
//		myThread3.setPriority(1);
		myThread.start();
//		try {
//			myThread.join();
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
		myThread2.start();
//		myThread3.start();
//		System.out.println(Thread.currentThread().getName());
	}
}

 实现效果:

由此可见暂停当前执行的线程对象,并执行其他线程也是有随机性的

举例:

相当于一群人在排队上公交,但是到A的时候,他突然说:"我不想排队了,我们来竞赛上公交吧,谁抢到谁就先上!".

所以有可能是A抢到上公交也可能是其他人抢到上公交的机会

后台线程

先贴文档,然后贴一下代码

自定义线程类代码:

package textDemo;
public class MyThread extends Thread{
	public  MyThread() {
		
	}
	
	public MyThread(String name) {
		super(name);
	}
	
	
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName()+":"+i);
		}
	}
}

测试类代码:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread myThread2 = new MyThread();
		//设置线程的名字
		myThread.setName("关羽");
		myThread2.setName("张飞");
		
		myThread.setDaemon(true);
		myThread2.setDaemon(true);
		
		myThread.start();
		myThread2.start();
		
		Thread.currentThread().setName("刘备");
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName()+":"+i);
		}
		
	}
}

运行结果:

不难发现当主线程运行完后其他守护线程都自己"消失",

例:刘备死了,关羽和张飞也觉不苟活,但是通过观察发现关羽和张飞还会跑一段距离的,=--=,自杀还需要时间对吧

所以让高速跑起来的线程刹车肯定有惯性,还要先跑一段然后停下来

中断线程

先来说一下过时的stop()方法

下面是代码:

自定义线程类:

package textDemo;

import java.util.Date;

import com.sun.xml.internal.ws.api.databinding.DatabindingConfig;

public class MyThread extends Thread{
	public  MyThread() {
		
	}
	
	public MyThread(String name) {
		super(name);
	}
	
	
	@Override
	public void run() {
		System.out.println("程序开始");
		for (int i = 0; i < 10; i++) {
			System.out.println(getName()+":"+i+" Time: "+new Date().toLocaleString());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("程序结束");
	}
}

测试类:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		MyThread myThread2 = new MyThread();
		//设置线程的名字
		myThread.setName("A");
		myThread2.setName("B");
		
		myThread.setDaemon(true);
		myThread2.setDaemon(true);
		
		myThread.start();
		myThread2.start();
		
		try {
			Thread.sleep(3000);
			myThread.stop();
			myThread2.stop();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
}

运行结果:

运行到3秒后直接停止两个线程,下面的代码都没有执行

如果想要让他继续执行下面的代码该怎么办呢?如下方法

使用interrupt()方法代码:

package textDemo;

import java.util.Date;

import com.sun.xml.internal.ws.api.databinding.DatabindingConfig;

public class MyThread extends Thread{
	public  MyThread() {
		
	}
	
	public MyThread(String name) {
		super(name);
	}
	
	
	@Override
	public void run() {
		System.out.println("程序开始 "+new Date().toLocaleString());
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				System.out.println("程序中断");
			}
		
		System.out.println("程序结束 "+new Date().toLocaleString());
	}
}

测试类代码:

package textDemo;

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		//设置线程的名字
		myThread.setName("A");
		
		
		myThread.start();
		
		try {
			Thread.sleep(3000);
			myThread.interrupt();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
}

运行结果:

:

观察发现interrupt()方法是通过抛出异常来中断线程的

与其说中断线程还不如说是如果线程在调用 Object 类的 wait()wait(long)wait(long, int) 方法,或者该类的 join()join(long)join(long, int)sleep(long)sleep(long, int) 方法过程中受阻,则其中断状态将被清除,然后抛出异常来进行中断

有些像计算机网络中运输层中等待停止协议中的死锁问题=-=个人感觉差不多

小白理解,请大牛提意见

猜你喜欢

转载自blog.csdn.net/acDream_/article/details/81384457