进程
进程:正在运行的应用程序
我们一个应用程序在运行过程中,会执行不同的任务,那么没一个任务,我们称之为线程
线程要依赖与进程,一个进程至少要有一个线程。
进程是拥有资源的基本单位,线程是CPU调用的基本单位
并发与并行
并发:指的是逻辑上的同时发生
并行:指的是物理上的同时发生
什么是并发 ?
并发 : 指应用能够交替执行不同的任务, 其实并发有点类似于多线程的原理, 多线程并非是如果你开两个线程同时执行多个任务, 执行, 就是在你几乎不可能察觉到的速度不断去切换这两个任务, 已达到
“同时执行效果”, 其实并不是的, 只是计算机的速度太快, 我们无法察觉到而已.就类似于你, 吃一口饭喝一口水, 以正常速度来看, 完全能够看的出来, 当你把这个过程以n倍速度执行时…可以想象一下.
什么是并行 ?
并行 : 指应用能够同时执行不同的任务, 例:吃饭的时候可以边吃饭边打电话, 这两件事情可以同时执行
多线程
什么是线程?
在一个进程内部又可以执行多个任务,而这每一个任务我们就可以看成是一个线程。是程序使用CPU的基本单位。
多线程有什么意义呢?
线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
多线程的作用不是提高执行速度,而是为了提高应用程序的使用率。
直白话就是通过多线程来抢夺CPU的使用率
Java中多个线程,执行是随机性的,因为我Java采用的线程调度模型是抢占式调度,线程优先级高的优先使用CPU的执行权,优先级一样,就是随机抢占
创建一个接口的三种方式
方式一:Thread类
Thread中的方法
线程类,如果想开启线程,需要创建一个类,继承Thread,重写Thread类中的run方法,创建我们写的这个子类对象,开启线程,让他执行run方法里面的代码。
public void run()
run方法里面的代码就是需要线程来执行的代码,一般我们会在run方法里面进行一些耗时操作。
另外,MyThread myThread = new MyThread(); myThread.run不是开启线程,只是普通的new对象调用方法。
public void start()
开启线程的正确方法,MyThread myThread = new MyThread(); myThread.start();
该线程开始执行,JAVA虚拟机去调用run方法
myThread.start();不能重复开启线程,否则报错。
void setName(String name)
设置线程名称
MyThread th1 = new MyThread();
th1.setName(“刘亦菲”);
public static void sleep(long millis)
让线程休眠一段时间,括号里面是单位是毫秒,是一种阻塞状态。
th1.sleep(1000)等待1秒钟再执行
public void interrupt()
打断线程的阻塞状态,让线程继续运行
public final int getPriority()
返回线程的优先级。
public final void setPriority(int newPriority)
设置线程的优先级。可以设置为1,5,10,Thread.MIN_PRIORITY,Thread.MAX_PRIORITY
th1.setOriority(1)
th1.setOriority(5)
th1.setOriority(10)
th1.setOriority(Thread.MIN_PRIORITY)
th1.setOriority(Thread.MAX_PRIORITY)
public static void yield()
线程礼让
public final void join()
等待该线程执行完毕了以后, 其他线程才能再次执行,
注意事项:在线程启动之后, 在调用方法
MyThread th1 = new MyThread(“张飞”);
MyThread th2 = new MyThread(“关羽”);
th1.start();
th1.join();
th2.start();
th2.join();
public final void setDaemon(Daemon(boolean on)
将该线程标记为守护线程或用户线程,当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。当用户线程,执行完之后,那么守护线程,必须里面死亡。设置为守护线程 该方法必须在启动线程前调用。
MyThread th1 = new MyThread(“张飞”);
MyThread th2 = new MyThread(“关羽”);
th1.setDaemon(true);
th2.setDaemon(true);
th1.start();
th2.start();
方式二:实现Runnable接口
-
创建线程的另一种方法是声明实现 Runnable 接口的类。
-
该类然后实现 run 方法。然后可以分配该类的实例。
-
在创建 Thread 时作为一个参数来传递并启动。
public class MyTest { public static void main(String[] args) { MyRunable myRunable = new MyRunable(); //Thread(Runnable target) //分配新的 Thread 对象。 //Thread(Runnable target, String name) //分配新的 Thread 对象。 Thread th = new Thread(myRunable,"王菲"); th.start(); Thread th2 = new Thread(myRunable,"谢霆锋"); th2.start(); } }
public class MyRunable implements Runnable { //Runable 任务
@Override
public void run() {
for (int i = 0; i < 100; i++) {
// System.out.println(this.getName+"==+i");
System.out.println(Thread.currentThread().getName() + "==" + i);
}
}
}
方式三:实现 Callable接口
A:
实现 Callable 接口。相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
B:
执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。FutureTask 是 Future 接口的实现类
C:
实现步骤
1. 创建一个类实现Callable 接口
2. 创建一个FutureTask类将Callable接口的子类对象作为参数传进去
3. 创建Thread类, 将FutureTask对象作为参数传进去
4. 开启线程
Callable 返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。
Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
FutureTask<Integer> integerFutureTask = new FutureTask<>(myCallable);
Thread th = new Thread(integerFutureTask);
th.start();
//获取线程执行完之后,返回的结果
Integer integer = integerFutureTask.get();
System.out.println(integer);
}
}
public class MyCallable implements Callable<Integer> {
//需要线程来执行的方法
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+" aaaaaa");
return 100;
}
}
编写程序,完成多个窗口共卖100张票的程序,并测试。
public class Mytest2 {
public static void main(String[] args) {
CellRunable cellRunable = new CellRunable();
Thread th1 = new Thread(cellRunable);
Thread th2 = new Thread(cellRunable);
Thread th3 = new Thread(cellRunable);
th1.setName("1号窗口");
th2.setName("2号窗口");
th3.setName("3号窗口");
th1.start();
th2.start();
th3.start();
}
}
public class CellRunable implements Runnable{
static int piao = 100;
static Object obj = new Object();
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if (piao>0){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在售卖 " + (piao--) + " 张票");
}
lock.unlock();
}
}
}