导学了解
进程:程序的基本执行实体
更加通俗的讲:一个软件执行后,它就是一个进程,绿色的内容都是一个进程。
线程是操作系统能够进行运算调度的最小单位。它被包含在进程当中,是进程中的实际运作单位。
可以这样理解: 用没有用过360安全卫士,它上面的每个功能都相当于进程,很多进程能够同时的运行,并且互相没有产生问题。进程类似于应用中互相独立,可以同时运行的功能。很多的线程合在一起就形成了多线程。
Java多线程是指在Java程序中同时运行多个线程,每个线程都可以独立执行不同的任务。Java多线程可以提高程序的并发性和响应性,使得程序可以同时处理多个任务,提高程序的效率。Java中的多线程可以通过继承Thread类或实现Runnable接口来创建线程,也可以使用线程池来管理线程。同时,Java提供了丰富的多线程API,如synchronized关键字、wait()和notify()方法等,来帮助开发者更好地控制线程的并发访问。
通过重写父类Thread方法中的run方法实现线程
注意:线程的开启是通过使用start方法来开启线程,而并非是通过使用调用run方法,通过类的对象去调用run方法,只能是一个普通的调用,并不能开启线程。
package thread_study;
public class demo1 {
public static void main(String[] args) {
MyThread1 thread = new MyThread1();
MyThread1 thread2 = new MyThread1();
thread.setName("线程一");
thread2.setName("线程而");
//注意:这里的线程开发则是通过start方法去开启,并非是通过调用run方法,调用run方法则是普通的调用
thread.start();
thread2.start();
}
}
class MyThread1 extends Thread{
/*
开启线程的第一种方法:
定义个类去继承线程类Thread
重写类中的run方法
创建子类的对象,并且去开启线程
*/
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println("这是"+getName()+"的内容输出");
}
}
}
package thread_study;
public class demo2 {
public static void main(String[] args) {
MyThread2 myThread2 = new MyThread2();
Thread thread = new Thread(myThread2);
Thread thread2 = new Thread(myThread2);
thread.setName("线程一");
thread2.setName("线程二");
thread.start();
thread2.start();
}
}
class MyThread2 implements Runnable{
/*
开启线程的第二种方法:
定义个类实现R
重写类中的run方法
创建子类的对象,并且去开启线程
*/
@Override
public void run() {
for (int i=0;i<10;i++){
// Thread thread = Thread.currentThread();
System.out.println("这是"+Thread.currentThread().getName()+"的内容输出");
}
}
}
注意:这个方法拥有返回值
package thread_study;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//第三种方法去实现线程
public class MyThread3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
多线程实现的第三种方法:可以接收到线程运行的结果
通过实现Callable接口,重写call方法
然后通过创建FutureTask对象(通过此类可以实现对多线程运行结果的管理
*/
MyThread_test myThread_test = new MyThread_test();
FutureTask futureTask = new FutureTask<>(myThread_test);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
}
class MyThread_test implements Callable {
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i <= 100; i++) {
sum =sum +i;
}
return sum;
}
}
可以设置线程的优先顺序,优先级高的线程会优先去执行,但是这种方法的设置,并不意味着优先级高的一定比优先级底的先执行完,因为在线程执行是抢占式,谁先抢到谁先去执行,所以说优先级高的并不是一定的比线程优先级低的先行执行完成。
设置:线程二的优先级比线程的一的优先级高
package thread_study;
public class MyThread04 {
public static void main(String[] args) {
Thread04_test thread04_test= new Thread04_test();
Thread thread = new Thread(thread04_test,"线程一");
Thread thread2 = new Thread(thread04_test,"线程二");
//获取当前线程的优先级
// System.out.println(Thread.currentThread().getPriority());
//设置进程的优先级默认为5 1最小 10最大
thread.setPriority(1);
thread2.setPriority(10);
thread.start();
thread2.start();
}
}
class Thread04_test implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"@"+i);
}
}
}
/*
* 线程优先级低的可能比优先级的高的线程先行执行完,只是这中的概率比较低,但是还是有一种概率发生。如果不进行任何的设置,那么这个线程的默认优先级数值为5
*
* */
大概率的情况下:线程二先行执行完,然后线程一再执行完
小概率的情况下:线程二后执行完,线程一先行执行完
守护线程:可以理解为当一个线程结束时,守护线程也会陆续的结束 ,qq聊天界面,有着聊天和传输文件的功能,聊天是一个线程,传输文件也是一个线程,但是当一个qq聊天界面关闭时,那么传输文件的哪个界面,也就关闭了 * 守护线程当线程结束时,那么守护线程则没有没有存在的必要了,但是它不会立刻的结束,他会慢慢的结束。
案例实现线程二对线程一的守护,当线程一结束时,他的守护线程二也会陆陆续续的停掉
package thread_study;
public class MyThread05 {
public static void main(String[] args) {
/*
* 守护线程:可以理解为当一个线程结束时,守护线程也会陆续的结束
* qq聊天界面,同时聊天和传输文件,聊天是一个线程,传输文件也是一个线程,但是当一个qq聊天界面关闭时,那么传输文件的哪个界面,也就关闭了
* 守护线程当线程结束时,那么守护线程则没有没有存在的必要了,但是它不会立刻的结束,他会慢慢的结束
*
* */
//案例实现线程二对线程一的守护,当线程一结束时,他的守护线程二也会陆陆续续的停掉
Thread05_demo1 thread05_demo1 = new Thread05_demo1();
Thread05_demo2 thread05_demo2 = new Thread05_demo2();
thread05_demo1.setName("线程一");
thread05_demo2.setName("线程二");
//把线程二设置成守护线程
thread05_demo2.setDaemon(true);
thread05_demo1.start();
thread05_demo2.start();
}
}
class Thread05_demo1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"@"+i);
}
}
}
class Thread05_demo2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
线程二守护线程一,当线程一执行完之后,线程二就陆陆续续的结束,并不能直接的结束
出让线程:Java的线程时抢占式,多线程过程中,谁先抢到线程,谁就会先执行 *
也可以通过yield出让本线程的执行权,出让执行权,但是出让这个机会,出让执行权的线程依旧可以再次的抢夺,可以通过此方法实现尽可能的均匀 *
静态方法,可以通过类去直接的调用
package thread_study;
public class MyThread06 {
public static void main(String[] args) {
/*
* 出让线程:Java的线程时抢占式,多线程过程中,谁先抢到线程,谁就会先执行
* 也可以通过yield出让本线程的执行权,出让执行权,但是出让这个机会,出让执行权的线程依旧可以再次的抢夺,可以通过此方法实现尽可能的均匀
* 静态方法,可以通过类去直接的调用
* */
MyThread06_test myThread06_test1 = new MyThread06_test();
MyThread06_test myThread06_test2 = new MyThread06_test();
myThread06_test1.setName("线程一");
myThread06_test2.setName("线程二");
myThread06_test1.start();
myThread06_test2.start();
}
}
class MyThread06_test extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
//出让当前CPU的执行权
Thread.yield();
}
}
}
插入线程,在一个线程的前面,在插入一个线程
通过join方法来实现
main方法默认的情况下也是一个程序
在main方法去执行程序,然后再通过join方法去再main方法前添加一个程序
package thread_study;
public class MyThread07 {
public static void main(String[] args) throws InterruptedException {
/*
插入线程,在一个线程的前面,在插入一个线程
通过join方法来实现
main方法默认的情况下也是一个程序
在main方法去执行程序,然后再通过join方法去再main方法前添加一个程序
* */
// 通过join方法实现MyThread07_test线程的插入
MyThread07_test myThread07_test = new MyThread07_test();
myThread07_test.setName("线程");
myThread07_test.start();
myThread07_test.join();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
class MyThread07_test extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
线程插队成功
//同步代码块
//给线程添加一个锁,保证的是只有一个线程去执行,当代码完全执行完毕后,再释放锁,不会出现数据的重复,和超出范围值
//注意锁的对象必须是唯一的,可以通过字节码对象,因为带idea中类的创建必须是唯一的
* 实现三个售票点,正在销售,总共有100张票
* 在正常的开发过程中,几个线程同时执行代码,那么在同一时间而言,就有可能有多个线程去执行同一行代码
* 这样就容易出现代码的重复,还会容易出现,超出范围等问题,锁的产生帮助我们去解决这个问题
package thread_study;
public class MyThread08 {
public static void main(String[] args) {
/*
* 实现三个售票点,正在销售,总共有100张票
* 在正常的开发过程中,几个线程同时执行代码,那么在同一时间而言,就有可能有多个线程去执行同一行代码
* 这样就容易出现代码的重复,还会容易出现,超出范围等问题,锁的产生帮助我们去解决这个问题
* */
MyThread08_test myThread08_test1 = new MyThread08_test();
MyThread08_test myThread08_test2 = new MyThread08_test();
MyThread08_test myThread08_test3 = new MyThread08_test();
myThread08_test1.setName("售票点一");
myThread08_test2.setName("售票点二");
myThread08_test3.setName("售票点三");
myThread08_test1.start();
myThread08_test2.start();
myThread08_test3.start();
}
}
class MyThread08_test extends Thread{
static int ticket = 1;
@Override
public void run() {
while (true){
//同步代码块
//给线程添加一个锁,保证的是只有一个线程去执行,当代码完全执行完毕后,再释放锁,不会出现数据的重复,和超出范围值
//注意锁的对象必须是唯一的,可以通过字节码对象,因为带idea中类的创建必须是唯一的
synchronized (MyThread08_test.class){
if(ticket<=100){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "正在卖第"+ticket +"票");
ticket ++;
}else {
break;
}
}
}
}
}
package thread_study;
public class MyThread09 {
public static void main(String[] args) {
MyThread09_test myThread09_test = new MyThread09_test();
Thread thread1 = new Thread(myThread09_test);
Thread thread2 = new Thread(myThread09_test);
Thread thread3 = new Thread(myThread09_test);
thread1.setName("窗口一");
thread2.setName("窗口二");
thread3.setName("窗口三");
thread1.start();
thread2.start();
thread3.start();
}
}
class MyThread09_test implements Runnable{
int ticket = 1;
@Override
public void run() {
while (true){
try {
if (demo1()) break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private synchronized boolean demo1() throws InterruptedException {
if(ticket>100){
return true;
}else{
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + "正在卖第" +ticket + "票");
ticket ++;
}
return false;
}
}
synchronized:这个上锁是自动化,只要有线程执行了方法,就会上锁,但是只有当方法完全之后,才要释放锁
通过lock来实现,上锁和释放锁,通过我们的手动的方法去上锁和释放锁,并非像synchronized智能锁一样不需要手动的添加。
package thread_study;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyThread10 {
public static void main(String[] args) {
/*
* synchronized:这个上锁是自动化,只要有线程执行了方法,就会上锁,但是只有当方法完全之后,才要释放锁
* 通过lock来实现,上锁和释放锁
* */
MyThread10_test myThread10_test = new MyThread10_test();
Thread thread = new Thread(myThread10_test);
Thread thread2 = new Thread(myThread10_test);
Thread thread3 = new Thread(myThread10_test);
thread.setName("线程1");
thread2.setName("线程2");
thread3.setName("线程3");
thread.start();
thread2.start();
thread3.start();
}
}
class MyThread10_test implements Runnable{
static int ticket = 1;
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
//上锁
lock.lock();
try {
if(ticket<=100){
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + "正在卖第"+ticket +"票");
ticket ++;
}else {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally { //把释放锁放在finally可以确保,无论如何释放锁都会被执行
//释放锁
lock.unlock();
}
}
}
}
这种模式是一种十分经典的多线程协作方式,它可以让线程结果更加的均匀,假设只有两个线程的情况下,这种机制会线程一实现一次,线程二实现一次,轮流的执行。
案例实现:消费者生产者模式,生产者做出一份,那么消费者就消费一份,如果消费者没有消费完,那么生产者就需要等待,如果生产者没有生产一份,那么消费者就要等待。
package wait_notify;
public class Cooker extends Thread {
@Override
public void run() {
while (true) {
synchronized (Desk.object) {
if(Desk.count==0){
break;
}else {
if(Desk.foodlie==1){
try {
//生产者等待
Desk.object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(getName()+"要开始做饭了。。。");
Desk.foodlie=1;
//生产者唤醒消费者
Desk.object.notifyAll();
}
}
}
}
}
}
package wait_notify;
public class foodlie extends Thread {
@Override
public void run() {
while (true){
synchronized (Desk.object){
if(Desk.count==0){
break;
}
else {
if (Desk.foodlie==0){
try {
//消费者等待
Desk.object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
Desk.count--;
System.out.println(getName()+"开始吃饭"+"还剩下"+Desk.count+"碗");
//消费者唤醒生产者
Desk.object.notifyAll();
Desk.foodlie=0;
}
}
}
}
}
}
package wait_notify;
public class Desk {
//定义消费者总共吃多少量
public static int count =10;
//定义锁对象
public static Object object = new Object();
//定义桌子上是否有食物 o:表示没有 1:表示有食物
public static int foodlie = 0;
}
package wait_notify;
public class Test {
public static void main(String[] args) {
foodlie foodlie = new foodlie();
Cooker cooker =new Cooker();
foodlie.setName("消费者");
cooker.setName("厨师");
foodlie.start();
cooker.start();
}
}