Java多线程
【摘要】 进程与线程进程(Process):进程是程序的一次动态执行过程,它经历了从代码加载、执行、到执行完毕的一个完整过程;同时也是并发执行的程序在执行过程中分配和管理资源的基本单位,竞争计算机系统资源的基本单位。线程(Thread):线程可以理解为进程中的执行的一段程序片段,是进程的一个执行单元,是进程内可调度实体,是比进程更小的独立运行的基本单位,线程也被称为轻量级进程。 一、多线程的实现 1...
进程与线程
进程(Process):进程是程序的一次动态执行过程,它经历了从代码加载、执行、到执行完毕的一个完整过程;同时也是并发执行的程序在执行过程中分配和管理资源的基本单位,竞争计算机系统资源的基本单位。
线程(Thread):线程可以理解为进程中的执行的一段程序片段,是进程的一个执行单元,是进程内可调度实体,是比进程更小的独立运行的基本单位,线程也被称为轻量级进程。
一、多线程的实现
1.继承Thread类
- 方式1:继承Thread类
- 定义一个类MyThread继承Thread类
- 在MyThread类中重写run0方法
- 创建MyThread类的对象
- 启动线程
案例分析:
package com.Thread;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(i);
}
}
}
package com.Thread;
public class MyThreadTest {
public static void main(String[] args) {
MyThread t1=new MyThread();
MyThread t2=new MyThread();
// t1.run();
// t2.run();
//start()导致此线程开始执行,java虚拟机调用此线程的run方法
t1.start();
t2.start();
}
}
1.设置和获取线程名称
package com.Thread;
public class MyThread extends Thread {
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
//getName()获取线程名称
System.out.println(getName()+":"+i);
}
}
}
package com.Thread;
public class MyThreadTest {
public static void main(String[] args) {
// MyThread t1=new MyThread();
// MyThread t2=new MyThread();
/* //设置线程名称(方式一)
t1.setName("小马哥");
t2.setName("小飞侠");*/
// t1.run();
// t2.run();
//start()导致此线程开始执行,java虚拟机调用此线程的run方法
//设置线程名称(方式二)
MyThread t1=new MyThread("小马哥");
MyThread t2=new MyThread("小飞侠");
t1.start();
t2.start();
}
}
2.线程优先级
- Thread类中设置和获取线程优先级的方法
- public final int getPriority0):返回此线程的优先级
- public final void setPriority(int newPriority):更改此线程的优先级
案例分析:
package com.priority;
public class MyPriority extends Thread {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(getName()+":"+i);
}
}
}
package com.priority;
public class MyPriorityTest {
public static void main(String[] args) {
MyPriority p1=new MyPriority();
MyPriority p2=new MyPriority();
MyPriority p3=new MyPriority();
p1.setName("线程一");
p2.setName("线程二");
p3.setName("线程三");
// System.out.println(Thread.NORM_PRIORITY); //5
// System.out.println(Thread.MAX_PRIORITY); //10
// System.out.println(Thread.MIN_PRIORITY); //1
//设置线程优先级
p1.setPriority(1);
p2.setPriority(7);
p3.setPriority(10); //线程等级越高获取cpu时间片的几率高
p1.start();
p2.start();
p3.start();
}
}
3.线程控制
方法名 | 说明 |
---|---|
static void sleep(long millis) | 使当前正在执行的线程停留(暂停执行)指定的毫秒数 |
void join() | 等待这个线程死亡 |
void setDaemon(boolean on) | 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出 |
案例分析:
package com.control;
public class ThreadSleep extends Thread {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package com.control;
public class ThreadSleepTest {
public static void main(String[] args) {
ThreadSleep s1=new ThreadSleep();
ThreadSleep s2=new ThreadSleep();
ThreadSleep s3=new ThreadSleep();
s1.setName("小马哥");
s2.setName("小飞侠");
s3.setName("老六");
s1.start();
s2.start();
s3.start();
}
}
package com.control;
public class ThreadJoin extends Thread{
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(getName()+":"+i);
}
}
}
package com.control;
public class ThreadJoinTest {
public static void main(String[] args) {
ThreadJoin j1=new ThreadJoin();
ThreadJoin j2=new ThreadJoin();
ThreadJoin j3=new ThreadJoin();
j1.setName("老大");
j2.setName("老二");
j3.setName("老三");
j2.start();
//当j2执行完之后,j1,j3才开始执行
try {
j2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
j1.start();
j3.start();
}
}
package com.control;
public class ThreadDaemon extends Thread {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(getName()+":"+i);
}
}
}
package com.control;
public class ThreadDaemonTest {
public static void main(String[] args) {
ThreadDaemon d1=new ThreadDaemon();
ThreadDaemon d2=new ThreadDaemon();
d1.setName("张飞");
d2.setName("关羽");
//设置主线程,主线程执行完毕之后,守护线程也会很快的结束
Thread.currentThread().setName("刘备");
//设置守护线程
d1.setDaemon(true);
d2.setDaemon(true);
d1.start();
d2.start();
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
4.线程的生命周期
2.实现Runnable接口的方式实现多线程
- 方式2:实现Runnable接口
- 定义一个类MyRunnable实现Runnable接口
- 在MyRunnable类中重写run()方法
- 创建MyRunnable类的对象
- 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
- 启动线程
- 多线程的实现方案有两种
- 继承Thread类
- 实现Runnable接口
- 相比继承Thread类,实现Runnable接口的好处
- 避免了Java单继承的局限性
- 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好子的体现了面向对象的设计思想。
案例分析:
package com.Runnable;
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
package com.Runnable;
public class MyRunableTest {
public static void main(String[] args) {
MyRunnable m=new MyRunnable();
Thread t1=new Thread(m,"小马哥");
Thread t2=new Thread(m,"小飞侠");
t1.start();
t2.start();
}
}
二、线程同步
- 锁多条语句操作共享数据,可以使用同步代码块实现
- 格式:
synchronized(任意对象){
多条语句操作共享数据的代码
)
- synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看成是一把锁
同步的好处和弊端 - 好处:解决了多线程的数据安全问题
- 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率
案例分析:
package com.SellTicketTest;
public class SellTicket implements Runnable {
private int ticket=100;
private Object obj=new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在售出第" + ticket + "张票");
ticket--;
}
}
}
}
}
package com.SellTicketTest;
public class SellTicketTest {
public static void main(String[] args) {
SellTicket ticket=new SellTicket();
Thread t1=new Thread(ticket,"窗口一");
Thread t2=new Thread(ticket,"窗口二");
Thread t3=new Thread(ticket,"窗口三");
t1.start();
t2.start();
t3.start();
}
}
三、线程安全的类
/*
线程安全的类;
StringBuffer
Vector
HashtabLe
*/
public c1ass ThreadTest {
public static void main(string[] args){
StringBuffer sb = new StringBuffer();
StringBuilder sb2 = new StringBuilder();
Vector<String> v = new Vector<String>();
ArrayList<String> array = new ArrayList<string>();
Hashtable<String,String> ht = new Hashtable<String,string>();
HashNap<String,string> hm = new HashMap<String,string>();
List<String> list = Collections.synchronizedList(new ArrayList<String>());
}
}
四、Lock锁
- Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作Lock中提供了获得锁和释放锁的方法
- void lock():获得锁
- void unlock():释放锁
- Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化ReentrantLock的构造方法
- ReentrantLock():创建一个ReentrantLock的实例
案例分析:
package com.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyLock 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--;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
package com.lock;
import com.SellTicketTest.SellTicket;
public class MyLockTest {
public static void main(String[] args) {
MyLock ticket=new MyLock();
Thread t1=new Thread(ticket,"窗口一");
Thread t2=new Thread(ticket,"窗口二");
Thread t3=new Thread(ticket,"窗口三");
t1.start();
t2.start();
t3.start();
}
}
五、生产者消费者模式
- ava就提供了几个方法供我们使用,这几个方法在Object类中Object类的等待和唤醒方法:
方法名 | 说明 |
---|---|
void wait() | 导致当前线程等待,直到另一个线程调用该对象的notify)方法或notifyAll)方法 |
void notify() | 唤醒正在等待对象监视器的单个线程 |
void notifyAll() | 唤醒正在等待对象监视器的所有线程 |
案例分析:
class Box{
private int milk;
private boolean state=false;
public synchronized void put(int milk) {//同步代码块:执行这块代码后,所在线程加锁,不会被抢占使用权。
//这时其他线程要执行,需要wait()该线程,notify()其他线程
if(state) { //有奶,不再继续放,put的线程暂停,等待get线程拿出奶
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//state=false,没有奶,生产者放入奶,这是第i瓶
this.milk=milk;
System.out.println("生产者放入第"+this.milk+"瓶奶");
state=true; //有了奶,奶箱不为空,修改奶箱状态
notifyAll(); //唤醒其他所有线程(唤醒get线程,取出牛奶)
}
public synchronized void get() {
if(!state) { //state=false,没有奶,消费者没法拿出奶,只能等待
try {
wait(); //消费者的get行为/线程开始等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//state=true,有奶,可以拿出,这是第i瓶奶
System.out.println("消费者拿出第"+this.milk+"瓶奶");
state=false; //拿出以后,box空,修改box状态
notifyAll(); //唤醒其他所有线程(唤醒put线程,开始放入)
}
}
class Producer implements Runnable{
private Box b;
public Producer(Box b) {
this.b=b;
}
@Override
public void run() {
for(int i=1;i<11;i++) {
b.put(i);
}
}
}
class Customer implements Runnable{
private Box b;
public Customer(Box b) {
this.b=b;
}
@Override
public void run() {
while(true) {
b.get();
}
}
}
public class Milk {
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); //producer在线程1中
Thread t2=new Thread(c); //customer在线程2中
t1.start();
t2.start();
}
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)