线程 和进程
进程:
进程是程序的基本执行实体
线程:
进程是操作系统能够进行运算调度的最小单位,他被包含在进程之中,是进程中的实际运作单位
-
并发: 并发: 在同一时刻,又多个指令在单个cpu上交替执行
-
并行: 并行: 在同一时刻,有多个指令在多个cpu上同时执行
多线程的实现
- 继承Thread 该子类赢重写Thread类的run方法 以下是一个简单的例子: 第一步:创建一个Thread的子类,(MyThread) 第二步:在MyThread类里面重写run方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"你好" +i);
}
}
第三步:创建一个MyThread对象,调用start() 方法;
MyThread myThread = new MyThread();
MyThread myThread1 = new MyThread();
myThread.setName("这是线程1");
myThread1.setName("这是线程2");
myThread1.start();
myThread.start();
运行结果:
- 实现Runnable接口的方式进行实现 第一步:自己定义一个类实现Runnable接口(MyRun) 第二步:重写里面的run方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("这是线程");
}
}
第三步:创建自己的类的对象
MyRun myRun =new MyRun();
第四部:创建一个Thread类的对象,并开启线程
Thread thread = new Thread(myRun);
thread.start();
运行结果:
由于MyRun 是实现Runnable的接口 所以不能直接使用getName的方法,如果要用getName方法,首先要用在MyRun类里面调用currentThread 方法;
MyRun类:
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Thread t = Thread.currentThread();
System.out.println("这是线程"+t.getName());
}
}
调用处:
MyRun myRun =new MyRun();
Thread thread = new Thread(myRun);
Thread thread1= new Thread(myRun);
thread.setName("(线程1)");
thread1.setName("(线程2)");
thread.start();
thread1.start();
运行结果: 2.利用Callable接口和Future接口方式实现 第一步: 创建一个类实现Callable接口(MyCallable) 第二步: 重写call(是有返回值的,表示多线程运行的结果)
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 101; i++) {
sum = sum+i;
}
return sum;
}
第三步:创建MyCallable的对象(表示多线程要执行的任务)
MyCallable myCallable = new MyCallable();
第四部:创建FutureTask的对象(表示管理多线程运行的结果)
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
第五步:创建Thread类的对象,并启动 (表示线程)
Thread thread = new Thread(futureTask);
thread.start();
第六步: 获取结果
Integer result = futureTask.get();
System.out.println(result);
运行结果:
线程常见的成员方法
-
setName():给线程设置名字;
设置名字也可以用构造方法设置一个名字,(子类无法继承父类的构造方法,使用super调用父类的构造方法)
-
getname (): 获取线程的名字 (注意 如果没有给线程设置名字 线程默认的名字是Thread-0、Thread-1)
-
setPriority() 设置线程的优先级。数字越大,优先级越高,数字越小,优先级越低。范围为1-10 (默认的优先级是5)
-
getPriority () 获取线程的优先级(查看线程的优先级,返回的是一个数字) 注意 setPriority 设置的数字越大,代表的是线程抢占到cpu的概率大,优先级越大,并不代表一定先运行完
-
setDaemon(true); 守护线程 ,把该线程设置成守护线程,如果非守护线程运行结束,那么守护线程会自动停止运行(但
不是立刻
停止,会继续运行一小段时间。) -
出让线程/礼让线程
-
插入线程
线程的生命周期
- 新建: 创建线程对象
- 就绪:调用start方法之后(有执行权,没有执行资格)
- 运行:抢到cpu资源之后(有执行权,有执行资格),如果被其他线程抢走了cpu资源,那么线程会进入到就绪阶段, 如果线程遇到了sleep方法或者其他阻塞方法,则线程进入阻塞阶段,睡眠结束进入就绪状态 阻塞阶段没有执行权,也没有执行资格
- 死亡:run方法都执行了,线程死亡
锁
同步 锁:synchronized
synchronized (锁){ // 锁对象一定是唯一的
操作共享数据的代码
}
例如:电影院有三个窗口卖票,总共卖一百张票 Main类:
MyThread myThread = new MyThread();
myThread.setName("窗口1");
MyThread myThread2 = new MyThread();
myThread2.setName("窗口2");
MyThread myThread3 = new MyThread();
myThread3.setName("窗口3");
myThread.start();
myThread2.start();
myThread3.start();
MyThread类:
static int piao = 0;
@Override
public void run() {
while (true){
if (piao<100){
try {
Thread.sleep(10);
piao++;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(getName()+"卖出了第" +piao +"票");
}
}
}
此时会导致可能会多卖出票 票数大于100;这个是时候需要加入锁,等上一个线程执行完之后,线程再抢占cpu执行
MyThread加入死锁:此时锁里面的代码是轮流执行的
static int piao = 0;
static Object object = new Object();
@Override
public void run() {
while (true){
synchronized (object){
if (piao<100){
try {
Thread.sleep(10);
piao++;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(getName()+"卖出了第" +piao +"票");
}
}
}
}