进程是指运行中的应用程序,每一个进程都有独立的内存空间,一个应用程序可以同时执行多个进程。(当有程序未响应的时候你会打开任务管理器,里面显示的一堆东西就是进程。)
线程是指进程中的一个执行流程,一个线程可以由多个线程组成,即在一个进程中可以同时运行多个不同的线程,它们分别执行不同的任务。
线程的创建与启动
Java 提供了三种创建线程的方法:
1.通过继承 Thread 类本身;
2.通过实现 Runnable 接口;
3.通过 Callable 和 Future 创建线程。
多线程的第一种启动方式
1.自己定义一个类继承Thread类
2.重写里面的run()方法
3.创建子类的对象
public class MyThread extends Thread {
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"HelloWorld");
}
}
}
测试类:
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
//给线程起名字
t1.setName("线程1");
t2.setName("线程2");
t1.start();//输出100次HelloWord
t2.start();
}
多线程的第二种启动方法
1.自己定义一个类去实现Runablie接口
2.重写里面的run方法
3.创建自己的类的对象
4.创建一个Thread类的对象,并开启线程
public class MyRun implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
//获取当前线程对象
Thread t = Thread.currentThread();
System.out.println(t.getName()+":"+"HelloWorld");
}
}
}
测试类:
public static void main(String[] args) {
//创建MyRun的对象
//表示多线程要执行的任务
MyRun mr = new MyRun();
//创建线程对象
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
//给线程起名字
t1.setName("线程1");
t2.setName("线程2");
//开启线程
t1.start();
t2.start();
}
多线程的第三种实现方式
1.创建一个类MyCallable实现Callable接口
2.重写call方法(有返回值,表示多线程运行的结果)
3.创建MyCallable对象(表示多线程要执行的任务)
4.创建FutureTask的对象(作用管理多线程运行的结果)
5.创建Thread对象,并启动(表示线程)
public class MyCallable implements Callable<Integer> {
public Integer call() throws Exception {
//求1~100之间的和
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum = sum + i;
}
return sum;
}
}
测试类:
public static void main(String[] args) throws InterruptedException, ExecutionException {
//创建MyCallable对象(表示多线程要执行的任务)
MyCallable mc = new MyCallable();
//创建FutureTask的对象(管理多线程运行的结果)
FutureTask<Integer> ft = new FutureTask<>(mc);
//创建Thread对象,并启动(表示线程)
Thread t1 = new Thread(ft);
//启动线程
t1.start();
//获取多线程运行结果
Integer result = ft.get();
System.out.println(result);
}
线程命名和线程休眠
利用继承Thread类本身创建线程
public class MyThread extends Thread {
public MyThread() {
}
public MyThread(String name){
super(name);
}
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(getName()+"@"+i);
}
}
}
测试类:
public static void main(String[] args) throws Exception {
/*
* String getName() 返回线程的名字
* void setName(String name) 设置线程的名字(构造方法也可以设置名字)
*
* 1.如果没有给线程设置名字也是有默认名字的
* 格式:Thread-X(X序号,从0开始的)
* 2.如果给线程设置名字,可以用set方法,也可以用构造方法
*
* static Thread currentThread() 获取当前线程的对象
*
* 1.当java虚拟机启动之后,会自动启动多条线程
* 其中有一条就叫做main线程
* 作用是调用main方法并执行里面的代码
*
* static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
*
* 1.哪条线程执行到这个方法,线程就会停留对应时间,单位毫秒(1s = 1000ms)
* 2.到时间后会继续执行下面的其他代码
*/
//1.创建线程对象
MyThread t1 = new MyThread("飞机");
MyThread t2 = new MyThread("坦克");
//2.开启线程
t1.start();
t2.start();
//哪条线程执行到这个方法,此时获取的就是哪条线程的对象
Thread t = Thread.currentThread();
String name = t.getName();
System.out.println(name);//main
//休眠
System.out.println("11111");
Thread.sleep(5000);
System.out.println("22222");
}
设置,获取线程优先级
优先级越高的线程获得CPU执行的机会越大,而优先级越低的线程获得CPU执行的机会越小。线程的优先级用1~10的整数来表示,数字越大优先级越高。
通过实现Runnable接口创建线程
public class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
测试类:
public static void main(String[] args) {
/*
* setPriority(int newPriority) 设置线程的优先级
* final int getPriority() 获取线程的优先级
*
*
*
*/
//创建线程要执行的参数对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t1 = new Thread(mr,"飞机");
Thread t2 = new Thread(mr,"坦克");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
}
守护线程
利用继承Thread类本身创建线程1
public class MyThread1 extends Thread {
public void run() {
for (int i = 0; i <= 10; i++) {
System.out.println(getName()+"@"+i);
}
}
}
利用继承Thread类本身创建线程2
public class MyThread2 extends Thread {
public void run() {
for (int i = 0; i <= 100; i++) {
System.out.println(getName() + "@" + i);
}
}
}
测试类:
public static void main(String[] args) {
/*
* final void setDaemon(boolean on) 设置为守护线程
* 当其他的非守护线程执行完毕后,守护线程会陆续结束
*/
Thread t1 = new Thread();
Thread t2 = new Thread();
t1.setName("非守护");
t2.setName("守护");
//设置为守护线程
t2.setDaemon(true);
t1.start();
t2.start();
}
出让线程/礼让线程
让CPU重新调度,尽可能让结果均匀。
利用继承Thread类本身创建线程
public class MyThread extends Thread {
public void run(){
for (int i = 0; i <= 100; i++) {
System.out.println(getName()+"@"+i);
//出让CPU的执行权
Thread.yield();
}
}
}
测试类:
public static void main(String[] args) {
/*
* public static void yield() 出让线程/礼让线程
*/
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("飞机");
t2.setName("坦克");
t1.start();
t2.start();
}
插入线程/插队线程
利用继承Thread类本身创建线程
public class MyThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
测试类:
public static void main(String[] args) throws Exception {
/*
* public final void join() 插入线程/插队线程
*/
MyThread t = new MyThread();
t.setName("土豆");
t.start();
//表示把他这个线程,插入到当前线程之前。
//t:土豆
//当前线程:main线程
t.join();
//执行在main线程当中的
for (int i = 0; i < 10; i++) {
System.out.println("main线程"+i);
}
}
同步方法:
把synchronized关键字加到方法上去。
格式:修饰符synchronized返回值类型 方法名(方法参数) { }
特点1:同步方法是锁住里面的所有代码
特点2:锁对象不能指定自己。非静态:this。静态:当前类的字节码文件对象
Lock锁:
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作
Lock中提供了可以获得锁和释放锁的方法。
void lock():获得锁
void unlock():释放锁
Lock是接口所以不能实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock的构造方法
ReentrantLock():创建一个ReentrantLock的实例
static int ticket = 0;
static Lock lock = new ReentrantLock();
public void run() {
// 1.循环
while (true) {
// 2.同步代码块
// synchronized (MyThread.class){
lock.lock();
// 3.判断
try {
if (ticket == 100) {
break;
// 4.判断
} else {
Thread.sleep(10);
ticket++;
System.out.println(getName() + "在卖第" + ticket + "张票");
}
// }
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
// }
}
}
死锁
死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
java 死锁产生的四个必要条件:
1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。