概述:本文为Java多线程的基础知识点的第一部分,主要包括,通过继承Thread
来实现进程,线程调度,线程控制,run()
,start()
,join()
,sleep()
,setDaemon()
方法的使用,获取线程名字currentThread()
,线程同步,非静态锁,静态方法的锁,Lock锁,生产者与消费者问题,卖票问题。
线程:是进程中的单个顺序控制流,是一条执行路径
举例
方式一:继承Thread类
两个问题:
run()
是用来封装被线程执行的代码run()
:封装线程执行代码,直接调用,相当于普通方法的调用
start()
:启动线程;然后由JVM
调用此线程的run()
方法package com.one.container;
public class MyThreadDemo {
public static class MyThread extends Thread{
public MyThread(){}
public MyThread(String name){ // 自定义一个有参的构成方法
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; ++ i){
System.out.println(getName()+":"+i);
}
}
}
public static void main(String[] args){
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
my1.setName("高铁");
my2.setName("飞机");
my1.run(); // run方法 相当于单线程的
my2.run();
}
}
}
运行结果:
讲解代码:
package com.one.container;
import java.util.Scanner;
import java.util.Arrays;
public class Main {
// 通过继承Thread类来创造属于自己的MyThread
public static class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; ++ i){
System.out.println(i);
}
}
}
public static void main(String[] args){
// 创建两个对象
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
// my1.run(); run方法 相当于单线程的
// my2.run();
// 然后调用start方法
my1.start();
my2.start();
}
}
运行结果:
Thread.currentThread().getName()
:获取当当前的线程的名称
代码讲解:
public class MyThreadDemo {
public static class MyThread extends Thread{
public MyThread(){}
public MyThread(String name){ // 自定义一个有参的构成方法
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; ++ i){
System.out.println(getName()+":"+i);
}
}
}
public static void main(String[] args){
// 自定义的有参构造方法 不需要直接调用setName设置线程名称
MyThread my1 = new MyThread("高铁");
MyThread my2 = new MyThread("飞机");
my1.start();
my2.start();
// 返回对象前正在执行的线程对象的引用
System.out.println(Thread.currentThread().getName());
}
}
运行结果:
线程有两种调度模型
Java使用的抢占式的调度模型
假如计算机只有一个CPU,那么CPU在某一时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令,所以说多线程程序在执行的是有随机性,因为谁抢到CPU的使用权是不一定的
Thread
类中设置和获取线程优先级的方法
public final int getPriority()
: 返回此线程的优先级public final void setPriority(int new Priority)
: 更改此线程的优先级
线程默认优先级是5
;线程优先级的范围是:1-10
线程优先级高仅仅表示线程获取的CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到你想要大家结果public class MyThreadDemo {
public static class ThreadPriority extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i ++){
System.out.println(getName()+":"+i);
}
}
}
public static void main(String[] args){
// 创建进程对象
ThreadPriority tp1 = new ThreadPriority();
ThreadPriority tp2 = new ThreadPriority();
ThreadPriority tp3 = new ThreadPriority();
// public final int getPriority(); // 返回线程的优先级
System.out.println(tp1.getPriority());
System.out.println(tp2.getPriority());
System.out.println(tp3.getPriority());
// 设置进程名字
tp1.setName("高铁");
tp2.setName("飞机");
tp3.setName("汽车");
// public final void setPriority(int newPriority); 更改此线程的优先级
// tp1.setPriority(10000);
// System.out.println(Thread.MAX_PRIORITY); // 最高优先级
// System.out.println(Thread.MIN_PRIORITY); // 最小优先级
// System.out.println(Thread.NORM_PRIORITY); // 正常优先级
tp1.setPriority(Thread.NORM_PRIORITY);
tp2.setPriority(Thread.MAX_PRIORITY);
tp3.setPriority(Thread.MIN_PRIORITY);
// 启动线程
tp1.start();
tp2.start();
tp3.start();
}
}
运行结果:
学习代码:
public class MyThreadDemo {
public static class ThreadSleep extends Thread{
ThreadSleep(){}
ThreadSleep(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i ++){
System.out.println(getName()+":"+i);
try{
Thread.sleep(1000); // 休眠1s
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
ThreadSleep ts1 = new ThreadSleep("曹操");
ThreadSleep ts2 = new ThreadSleep("刘备");
ThreadSleep ts3 = new ThreadSleep("孙权");
ts1.start();
ts2.start();
ts3.start();
}
}
运行结果:
学习代码:
public class MyThreadDemo {
public static class ThreadJoin extends Thread{
ThreadJoin(){}
ThreadJoin(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i ++){
System.out.println(getName()+":"+i);
}
}
}
public static void main(String[] args){
ThreadJoin tj1 = new ThreadJoin("路飞");
ThreadJoin tj2 = new ThreadJoin("索隆");
ThreadJoin tj3 = new ThreadJoin("山治");
tj1.start();
try {
tj1.join(); // 等路飞 这个线程结束了 下面两个线程才会
// 执行
} catch (InterruptedException e) {
e.printStackTrace();
}
tj2.start();
tj3.start();
}
}
运行结果:
学习代码:
public class MyThreadDemo {
public static class ThreadDaemon extends Thread{
ThreadDaemon(){}
ThreadDaemon(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i ++){
System.out.println(getName()+":"+i);
}
}
}
public static void main(String[] args){
ThreadDaemon td1 = new ThreadDaemon("善毅");
ThreadDaemon td2 = new ThreadDaemon("山之助");
// 设置主线程名字为炭之郎
Thread.currentThread().setName("炭之郎");
// 设置守护线程
td1.setDaemon(true); // 要写在start的前面
td2.setDaemon(true);
// 鬼灭之刃三人组 炭之郎死后 二位小弟也要一同共赴黄泉
td1.start();
td2.start();
for (int i = 0; i < 10; ++ i){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
运行结果:
学习代码:
public class MyThreadDemo {
// 通过继承Runnable接口来实现多线程
public static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; ++ i){
// 获取当前进程的名字
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public static void main(String[] args){
MyRunnable my = new MyRunnable();
Thread t1 = new Thread(my, "高铁");
Thread t2 = new Thread(my, "飞机");
t1.start();
t2.start();
}
}
运行结果:
学习代码:
public class MyThreadDemo {
public static class SellTicket implements Runnable{
// 默认有100张票
private int ticket = 100;
@Override
public void run() {
while (true){
if (ticket > 0){
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
ticket --;
}
}
}
}
public static void main(String[] args){
SellTicket st = new SellTicket();
// 定义对象
Thread t1 = new Thread(st,"窗口1");
Thread t2 = new Thread(st,"窗口2");
Thread t3 = new Thread(st,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
运行结果:
学习代码:
public class MyThreadDemo {
public static class SellTicket implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true){
if (ticket > 0){
try { // 卖票的时候 添加休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
ticket --;
}
}
}
}
public static void main(String[] args){
SellTicket st = new SellTicket();
Thread t1 = new Thread(st,"窗口1");
Thread t2 = new Thread(st,"窗口2");
Thread t3 = new Thread(st,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
运行结果:
出现问题:
原因分析:
学习代码:
public class MyThreadDemo {
public static class SellTicket implements Runnable{
private int ticket = 100;
private Object obj = new Object(); // 在外面定义这个Object对象
@Override
public void run() {
while (true){
synchronized (obj){ // 不要在这里面定义这个对象 不然3个进程会产生3把锁 还是不能解决问题
if (ticket > 0){
try { // 卖票的时候 添加休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
ticket --;
}
}
}
}
}
public static void main(String[] args){
SellTicket st = new SellTicket();
Thread t1 = new Thread(st,"窗口1");
Thread t2 = new Thread(st,"窗口2");
Thread t3 = new Thread(st,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
运行结果:
学习代码:
public class MyThreadDemo {
public static class SellTicket implements Runnable{
private int ticket = 100;
private int x = 0;
@Override
public void run() {
try { // 卖票的时候 添加休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true){
if (x % 2 == 0){
synchronized (this){ // 非静态用的this这个锁
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
ticket --;
}
}
} else {
sellTicket();
}
}
}
private synchronized void sellTicket(){
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
ticket --;
}
}
}
public static void main(String[] args){
SellTicket st = new SellTicket();
Thread t1 = new Thread(st,"窗口1");
Thread t2 = new Thread(st,"窗口2");
Thread t3 = new Thread(st,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
运行结果:
学习代码:
public class SellTicket implements Runnable{
private static int ticket = 100;
private int x = 0;
@Override
public void run() {
try { // 卖票的时候 添加休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true){
if (x % 2 == 0){
synchronized (SellTicket.class){ // 静态的用这个锁
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
ticket --;
}
}
} else {
sellTicket();
}
}
}
private static synchronized void sellTicket(){
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket+"张票");
ticket --;
}
}
学习代码:
package Safe;
public class MyThreadDemo {
// 生产者类
public static class Producer implements Runnable{
private Box b;
public Producer(Box b) {
this.b = b;
}
@Override
public void run() {
for (int i = 1; i <= 5; ++ i){ // 放置牛奶
b.put(i);
}
}
}
// 消费者类
public static class Customer implements Runnable{
private Box b;
public Customer(Box b) {
this.b = b;
}
@Override
public void run() { // 获取牛奶
while(true){
b.get();
}
}
}
// 奶箱类
public static class Box{
// 定义一个成员变量 表示第x瓶牛奶
private int milk;
// 定义一个成员变量,表示奶箱的状态
private boolean state = false;
// 提供存储牛奶和获取牛奶的操作
// 存储牛奶
public synchronized void put(int milk){
// 如果有牛奶,等待消费
if (state){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果没有牛奶,就生产牛奶
this.milk = milk;
System.out.println("送奶工将第"+this.milk+"瓶奶放入奶箱");
// 生产完毕之后,修改奶箱状态
state = true;
// 唤醒其他等待线程
notifyAll();
}
// 获取牛奶
public synchronized void get(){
// 如果没有牛奶,等待生产
if(!state){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果有牛奶,就消费牛奶
System.out.println("用户拿到第"+this.milk+"瓶奶");
// 消费完毕之后,修改奶箱状态
state = false;
// 唤醒其他等待线程
notifyAll();
}
}
public static void main(String[] args){
// 创建奶箱对象,这是共享数据区域
Box b = new Box();
// 创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类种要调用存储牛奶的操作
Producer p = new Producer(b);
// 创建消费者对象,把牛奶对象作为构造方法参数传递,因为在这个类种要调用获取牛奶的操作
Customer c = new Customer(b);
// 创建两个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
// 启动线程
t1.start();
t2.start();
}
}
运行结果:
学习代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
public static class SellTicket implements Runnable{
private int ticket = 100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
while(true){
try {
lock.lock();
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
ticket--;
}
} finally { // 为了使得这个锁怎么都可以释放 所以要用到finally关键字
lock.unlock();
}
}
}
}
public static void main(String[] args){
SellTicket st = new SellTicket();
Thread t1 = new Thread(st, "窗口一");
Thread t2 = new Thread(st, "窗口二");
Thread t3 = new Thread(st, "窗口三");
t1.start();
t2.start();
t3.start();
}
}
运行结果: