Java基础——多线程

进程是指运行中的应用程序,每一个进程都有独立的内存空间,一个应用程序可以同时执行多个进程。(当有程序未响应的时候你会打开任务管理器,里面显示的一堆东西就是进程。)

线程是指进程中的一个执行流程,一个线程可以由多个线程组成,即在一个进程中可以同时运行多个不同的线程,它们分别执行不同的任务。

线程的创建与启动

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的资源。这样就形成了一个等待环路。

当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值