并发:指两个或多个事件在同一时间段内发生
并行:指两个或多个事件在同一时刻发生/同时发生
进程:指有关内存中运行的应用程序
线程:进程中的一个执行单元,一个程序运行后至少有一个进程,一个进程可以包含多个线程
线程存在优先级
实现步骤:
1、创建一个Thread类的子类
2、在Thread类的子类中重写Thread类中的run方法,设置线程任务
3、创建Thread类的子类对象
4、调用Thread类中的start方法,java虚拟机调用该线程的run方法
java程序属于抢占式调度,哪个线程的优先级高,就先调用哪个线程。
public class Thread1 extends Thread {
@Override
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println("子线程");
}
}
}
public class Test1 {
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
thread1.start();
for (int i = 0; i < 20 ; i++) {
System.out.println("主线程");
}
}
}
1、获取线程的名称
使用Thread类中的getName()
可以先获取到当先正在执行的线程,使用线程中的方法getName()获取线程的名称
public class Thread2 extends Thread {
@Override
public void run(){
String name = getName();
System.out.println(name);
// Thread thread = Thread2.currentThread();
// System.out.println(thread);
// String name1 = thread.getName();
// System.out.println(name1);
System.out.println(Thread2.currentThread().getName());
}
}
public class Test2 {
public static void main(String[] args) {
Thread2 thread2 = new Thread2();
thread2.start();
new Thread2().start();
new Thread2().start();
System.out.println(Thread2.currentThread().getName());
}
}
2、设置线程的名称
使用Thread类中的setName(name)
创建一个带参数的构造方法,参数传递线程的名称,调用父类的带参构造方法,把线程名称传递给父类,让父类给子线程起一个名字。
3、暂停执行
Thread类中的sleep方法,使当前正在执行的线程以指定的毫秒数暂停,毫秒数结束后,线程继续执行,这个方法是一个静态方法,Thread.sleep(1000);
实现Runnable接口
Thread类的构造方法可以传递Runnabel对象
实现步骤:
1、创建一个Runnable接口的实现类
2、在实现类中重写Runnable接口的run方法,设置线程任务
3、创建一个Runnable接口的实现对象
4、创建Thread类对象,构造方法传递Runnable接口的实现对象
5、调用Thread类创建对象的start方法
public class RunnableIpm implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20 ; i++) {
System.out.println(i);
}
}
}
public class Test3 {
public static void main(String[] args) {
RunnableIpm runnableIpm = new RunnableIpm();
Thread thread = new Thread(runnableIpm);
thread.start();
for (int i = 0; i < 20 ; i++) {
System.out.println(i);
}
}
}
1、避免单继承的局限性
一个类只能继承一个类
2、增强了程序的扩展性,解耦
实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离
匿名:没有名字
内部类:写在其他类的内部
匿名内部类:把子类继承父类,重写父类的方法,创建子类对象合成一步完成
把实现类实现类接口,重写接口中的方法,创建实现类对象合成一步完成
最终子类/实现对象 没有名字
格式:
new 父类/接口(){
重写父类/接口中的方法
}
public class Test4 {
public static void main(String[] args) {
new Thread(){
@Override
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}.start();
System.out.println("-------------------");
Runnable runnable = new Runnable(){
@Override
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName());
}
}
};
new Thread(runnable).start();
System.out.println("---------------------");
new Thread(new Runnable(){
@Override
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}).start();
}
}
等待唤醒机制
线程间的通讯wait()和notify():
创建一个线程,调用wait方法,放弃CPU的执行,进入到waiting状态(无限等待)
创建一个线程,调用notify方法,唤醒上面的线程
注意:
两个线程必须使用同步代码块包裹起来,保证等待和唤醒只有一个任务执行
同步使用的锁对象必须保证唯一
只有锁对象才能调用wait和notify方法
void wait()在其他线程调用此对象的notify方法或notifyAll()方法前,当前线程处于等待状态
void notify()唤醒在此对象监视器上等待的单个线程,会继续执行wait方法之后的代码
wait()和notify()方法必须要在同步代码块或者同步方法中使用,必须通过锁对象来调用这两个方法
public class WaitNotify {
public static void main(String[] args) {
Object object = new Object();
new Thread(){
@Override
public void run() {
// 保证等待和唤醒的线程只能有一个执行,需要同步
synchronized (object){
System.out.println("等待");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("唤醒后的代码");
}
}
}.start();
new Thread(){
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
System.out.println("唤醒");
object.notify();
}
}
}.start();
}
}
当程序第一次启动的时候,创建多个线程,保存到一个集合中,当我们想要使用线程的时候,就可以从集合中取出线程来使用。
Thread t = list.remove(0):返回的是被移除的元素(线程只能被一个任务使用)
当我们使用完毕线程,需要把线程归还给线程池
list.add(t)
类Executors
Executors类中的静态方法
static ExecutorService newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池
参数 int nThreads:创建线程池中包含的线程数量
返回值:ExecutorService接口,返回的是ExecutorService接口的实现类对象,我们可以使用ExeutorService接口接收
ExeutorService接口中的方法submit(Runnable task)提交一个Runnable任务执行
shutdown()关闭线程
使用步骤:
1、使用线程池的工厂类Executor里边提供的静态方法生产一个指定线程数量的线程池
2、创建一个类,实现Runnable接口,重写run方法,设置线程任务
3、调用ExecutorService中的submit,传递线程任务(实现类),开启线程,执行run方法
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new RunnableImpl2());
executorService.submit(new RunnableImpl2());
executorService.submit(new RunnableImpl2());
executorService.submit(new RunnableImpl2());
executorService.submit(new RunnableImpl2());
executorService.submit(new RunnableImpl2());
executorService.shutdown();
}
}
public class RunnableImpl2 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行");
}
}
原文:https://www.cnblogs.com/saonian450/p/12549552.html