线程
=================================
/*
*
* 了解并发和并行
* 什么是线程,什么是进程。
*
* 多线程:
* 并发:两个或多个事件在同一时间段内发生,cpu交替执行,效率低
* 并行:两个或多个事件在同一时刻发生(同时发生),cpu同时执行,速度快。
*
* 进程:任务管理器中进程 进入到内存的程序叫进程
* 硬盘永久存储ROM
* 内存:所有的应用程序都需要进入到内存中执行,临时存储RAM,进入到内存的程序叫进程
* 线程:是进程的执行单元
* 一个程序执行后至少有一个进程,一个进程可以包含多个线程
* CPU中央处理器,对数据进行计算,指挥电脑软件和硬件干活。
* 4核心-->8线程-->同时执行8个线程,8个线程在多个任务之间高速切换,速度提高8倍
* 线程属于进程,是进程的中的一个执行单元。
* cpu在多个进程之间高速切换,轮流执行多个线程,效率低。
* 多线程效率高,多个线程之间互不影响。
*
* 线程调度:
* 分时调度:轮流执行
* 抢占式调度:优先让优先级高的先执行。
*
* 主线程:
* 执行主方法(main)的线程
*
* 单线程程序: java程序只有一个线程
* 执行从main方法开始,从上往下依次执行
*
*/
public class XianCheng {
public static void main(String[] args) {
//单线程程序,小强先执行,旺财在执行,从上往下,依次执行
Person p1 = new Person("小强");
p1.run();
Person p2 = new Person("旺财");
p2.run();
}
}
---------------------------------------
public class Person {
private String name;
public void run(){
//定义循环
for(int i = 0;i < 20; i++){
System.out.println(name+"-->"+i);
}
}
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
---------------------------------------
public class MyThread extends Thread{
public void run(){
for(int i = 0; i < 20; i++){
System.out.println("run"+i);
}
}
}
---------------------------------------
/*
* java.long.Thread类描述线程的类,想要实现多线程,就必须继承Thread类
* 创建多线程程序的第一种方式,创建Thread类的子类
* 另一种方式,事项Runable接口。
*
* 创建一个Thread类的子类
* 在Thread类中重写Thread类中的run方法,设置线程任务(开启线程)
* 创建Thread类的子类对象
* 调用Thread类中的start方法,开启新的线程,执行run方法
* void start() 使该线程开始执行
*
*/
public class ThreadCls {
public static void main(String[] args) {
//多线程,每次抢到的资源时间都是不一样的,抢占资源,谁抢到就执行相应的代码
/*
* 因为MyThread这个类继承自了Thread,并重写了其中的run方法
* 那么这个类就是一个线程类。
* 开启线程类,调用其中的start()方法。
*/
MyThread mt = new MyThread();
//不能调用run方法
mt.start();
//
new MyThread().start();//匿名调用
for(int i = 0; i <20; i++){
System.out.println("main"+i);
}
}
}
=========================================
/*
* 多线程第一种方式。
* 继承自Thread类。
*/
public class MyThread extends Thread{
//
public MyThread(){
}
//这个方法是给带参输的名称来使用的。
public MyThread(String name){
//把线程名称传递给父类,让父类给子线程起一个名称 super(name);
}
//重写的run方法,调用start方法,执行这个run
@Override
public void run() {
//获取线程名称
System.out.println(Thread.currentThread().getName());
}
}
--------------------------------------------------------------------
/*
* 设置线程的名称
* 使用Thread中的方法setName
* void setName(String name)改变线程名称,,时之与参数name相同
* 创建一个带参数的构造方法,参数传递线程的名称,调用父类的带参构造方法,把现成的名称传递给父类
* 让父类Thread给子线程起一个名字
* Thread(String name) 分配新的Thread对象
*
*/
public class MyThreadTest {
public static void main(String[] args) {
//开启
MyThread mt = new MyThread();
mt.setName("设置为小强");//本来获取的为Thrad-0
mt.start();
//开启
new MyThread("设置为旺财").start();
}
}
-----------------------------------------------
/*
* Thread类中常用方法
* 获取线程名称1:
* 使用Thread类中的getName()
* String getName() 返回该线程的名称
* 获取线程的名称2:
* 先获取当前正在执行的线程,使用线程中的方法getName()获取线程的名称
* static Thread currentThread() 返回对当前正在执行的线程对象的应用
*
*
*
*/
public class ThreadCls extends Thread{
//重写run方法
@Override
public void run() {
// 获取线程名称,直接getName()就是线程的名称。
String name = getName();
System.out.println(name);
//获取线程名称
Thread t = Thread.currentThread();
System.out.println(t);//Thread[Thread-0,5,main]
String name2 = t.getName();
System.out.println(name2);
//连式编程
System.out.println(Thread.currentThread().getName());
}
}
-------------------------------------------
/*
* public static void sleep(Long millis):
* 静态的方法可以通过类名直接调用。
* 使当前线程以指定的毫秒暂停(暂时停止执行),毫秒结束后,线程继续执行
*
*
*/
public class ThreadSleep {
public static void main(String[] args) {
//模拟秒表
for(int i = 0; i <= 60; i++){
System.out.println(i);
//使用Thread中的静态的方法,类名直接调用,睡眠1秒钟
try {
//类名直接调用
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
------------------------------------------
/*
* 线程的名称:
* 主线程:main
* 新线程:Thread-0,Thread-1,Thread-2
*
* 设置线程的名称
* 使用Thread中的方法setName
* void setName(String name)改变线程名称,,时之与参数name相同
* 创建一个带参数的构造方法,参数传递线程的名称,调用父类的带参构造方法,把现成的名称传递给父类
* 让父类Thread给子线程起一个名字
* Thread(String name) 分配新的Thread对象
*
*/
public class ThreadTest {
public static void main(String[] args) {
//创建子类对象
ThreadCls mt = new ThreadCls();
//调用start,开启新的线程
mt.start();
new ThreadCls().start();
new ThreadCls().start();
//主线程
System.out.println(Thread.currentThread().getName());
}
}
====================================
Ranable
===================================
/*
* java.long.Runnable;
* 将类声明为Runable接口的实现类,重写run方法
* 它里面没有start对象,需要创建实现类对象Thread
*
* 创建多线程程序的第二种方法,实现Runable接口
* java.lang.Thread类的构造方法
* Thread(Runable target) 分配新的Thread对象
* Thread(Runable target,String name) 分配新的对象
*
* 创建一个Runable接口的实现类
* 在实现类中重写Runable接口的run方法,设置线程任务
* 创建一个Runable接口的实现类对象
* 创建Thread类对象,构造方法之中传递Runable接口的实现类对象
* 调用Thread类中的start方法,开启新的线程执行run方法
*
*
* 继承Thread类和实现Runable接口的区别:
* 实现Runable接口创建多线程的好处,避免了单继承的局限性,
* 一个类只能继承一个类,类继承了Thread就不能再继承其他类了。
* 实现Runable接口还可以继承其他的类,实现其它接口
* 增强了程序的扩展性,降低了程序的耦合性
* 设置线程任务和开启线程进行分离
* 实现类中重写了run方法,用来设置线程任务,创建Thread类对象,调用start方法,用来开启线程
* 推荐实现Runable接口。
*
*
*/
public class RunableCls {
public static void main(String[] args) {
//实现Runable接口,调用的时候还得new Thread(传递runable接口对象);
RunableImpl run = new RunableImpl();
//构造方法中调用RunableImpl的实现类
Thread t = new Thread(run);
//匿名对象实现人Runable接口。
// Thread t = new Thread(new RunableImpl());
//开启
t.setName("抖音");//自定义线程名称
t.start();
//main方法的线程
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
------------------------------------------------
/*
* 匿名内部类实现线程的创建:
* 匿名:没有名字
* 内部类:写在其他类内部的类
*
* 匿名内部类:简化代码
* new 父类/接口(){
* 重写父类/接口中的方法
* }
*
*/
public class InnerClassThread {
public static void main(String[] args) {
//线程的父类是Thread
new Thread(){
//重写run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"黑马");
}
}
}.start();
//线程的接口Runbable
//RunbableImpl
//Runnable r = new RunbableImpl();接口等于实现类-->多态
Runnable r = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"程序员");
}
}
};
new Thread(r).start();
//简化接口的方式,直接把r传进来
new Thread( new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"传智播客");
}
}
}).start();
}
}
------------------------------------------
public class RunableImpl implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
==============================
Lock
==============================
/*
* Lock接口:
* lock():获取锁
* unlock():施放锁
*
* 线程状态:
* 新建 运行 阻塞 死亡 休眠 永久等待
*
*/
public class LockCls {
}
------------------------------------
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* 实现卖票案例:
* 第三种解决方案
* java.util.concurrent.locks.Lock接口
* Lock接口中的方法:
* void Lock():获取锁
* void unLock():释放锁
*
* 使用步骤:
* java.util.concurrent.Locks.ReentrantLock implements Lock接口
* 在成员位置创建一个实现类,ReentrantLock对象
* 在可能出现代安全问题的代码前调用Lock接口,调用lock中的方法中获取锁
* 在可能出现安全问题的代码后调用Lock接口的方法unLock释放锁
*
* 创建锁是关键 new ReentrantLock();
* 锁对象和同步的概念不一样
* 同步是同步,锁对象是锁对象
* 锁对象在可能出现代码安全问题前面调用锁
* 锁对象在可能出现代码安全问题后面释放锁
*
*
*/
public class RunableImpl implements Runnable {
//定义多个线程共享的数据
private int ticket = 100;
//创建实现类。
Lock l = new ReentrantLock();
/* //设置线程任务卖票
@Override
public void run() {
//使用死循环让代码重复执行
while(true){
//在可能出现安全问题的代码前调用锁
l.lock();
//先判断票是否存在
if(ticket > 0){
try {
//让程序睡眠,当线程休眠的时候三个线程可能有两个多个就进来执行,让问题更清晰的出现
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第:"+ticket+"张票");
ticket--;
}
//在可能出现安全问题的代码后施放锁
l.unlock();
}
}*/
//设置线程任务卖票,无论程序是否异常都会把锁施放,提高程序的效率
@Override
public void run() {
//使用死循环让代码重复执行
while(true){
//在可能出现安全问题的代码前调用锁
l.lock();
//先判断票是否存在
if(ticket > 0){
try {
//让程序睡眠,当线程休眠的时候三个线程可能有两个多个就进来执行,让问题更清晰的出现
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+"-->正在卖第:"+ticket+"张票");
ticket--;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//在可能出现安全问题的代码后施放锁
l.unlock();
}
}
}
}
}
------------------------------------------
/*
* 线程安全问题:
* 使用线程同步技术解决线程问题
*/
public class ThreadSafe {
public static void main(String[] args) {
//创建一个实现类才能共享
RunableImpl run = new RunableImpl();
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
//调用start开启多线程
t0.start();
t1.start();
t2.start();
}
}
-------------------------------
/*
* 简单的线程通信:
* 等待和唤醒
* 线程之间的通信
* 创建一个消费者线程,告知老板需要购买的产品,调用wait,放弃cpu的执行,进入等待状态
* 创建一个来办线程,花5秒时间生产商品,,生产好之后唤醒顾客
*
* 注意事项:
* 顾客和老版线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行
* 同步锁对象必须保证是唯一的
*
* Object类中的方法
* 等待和唤醒。
* 需要创建Object类的对象。
* void wait()
* void notify()
*
*/
public class WaitAndNotify {
public static void main(String[] args) {
//创建等待和唤醒的对象。
Object obj = new Object();
//创建一个顾客线程消费者
new Thread(){
public void run() {
//一直等着
while(true){
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("告知老板需要的包子的数量");
try {
//父类的run方法没有抛异常只能try-catch
//走到这一步就开始,下面的代码不会执行,因为他在一直等待中,直到obj这个对象被唤醒
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//老板唤醒之后继续执行wait之后的代码
System.out.println("开吃");
System.out.println("---------------------------------");
}
}
}
}.start();;
//创建一个老板的线程
new Thread(){
//花5秒时间做包子
@Override
public void run() {
while(true){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (obj) {
System.out.println("老板5秒钟之后做好包子,告知顾客");
//唤醒
obj.notify();
}
}
}
}.start();;
}
}
------------------------------------------
/*
* 进入TimeWaiting(计时等待)
* 使用sleep(Long m)方法,在毫秒值结束之后,进入到可运行或阻塞状态
* 使用wait(Long m)方法,wait方法在毫秒结束之后,还没有被唤醒,就会自
* 动醒来,进入到可运行或者阻塞状态
* 唤醒的方法:
* void notify():唤醒单个
* void notifyAll():唤醒所有线程
* synchronized
* 保证等待和唤醒的线程只能有一个执行,需要使用同步技术
*
*/
public class WaitTimeAndNotify {
public static void main(String[] args) {
//创建锁对象
Object obj = new Object();
//创建一个顾客线程消费者
new Thread(){
public void run() {//一直等着
while(true){
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("顾客一告知老板需要的包子的数量");
try {
//父类的run方法没有抛异常只能try-catch
obj.wait(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//老板唤醒之后继续执行wait之后的代码
System.out.println("1开吃");
System.out.println("---------------------------------");
}}}
}.start();;
//创建一个顾客线程消费者
new Thread(){
public void run() {
//一直等着
while(true){
//保证等待和唤醒的线程只能有一个执行,需要使用同步技术
synchronized (obj) {
System.out.println("顾客二告知老板需要的包子的数量");
try {
//父类的run方法没有抛异常只能try-catch
//这个唤醒是随机的,所以顾客一告知也可能栓性顾客二来吃
obj.wait(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//老板唤醒之后继续执行wait之后的代码
System.out.println("2开吃");
System.out.println("---------");
}}}
}.start();
//创建一个老板的线程
new Thread(){
//花5秒时间做包子
@Override
public void run() {
while(true){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (obj) {
System.out.println("老板5秒钟之后做好包子,告知顾客");
//唤醒
// obj.notify();//此时只能随机的唤醒一个顾客
obj.notifyAll();//唤醒所有等待的线程
}}}
}.start();;
}
}
=========================
线程安全问题
===========================
/*
* 线程安全问题:
* 模拟买票案例
* 创建三个线程,对共享数据操作
* 出现重复票和-1的问题
*
* 三个线程一起抢夺cpu的执行权,可能抢夺到同一资源,并且都执行
*
* 使用线程同步技术解决线程问题
*/
public class ThreadSafe {
public static void main(String[] args) {
//创建一个实现类才能共享
RunableImpl run = new RunableImpl();
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
//调用start开启多线程,可依发现这三个人都卖掉了100张票,总共卖掉300张。
t0.start();
t1.start();
t2.start();
}
}
-----------------------------
/*
* 实现卖票案例:
*
*/
public class RunableImpl implements Runnable {
//定义多个线程共享的数据
private int ticket = 100;
//设置线程任务卖票
@Override
public void run() {
//使用死循环让代码重复执行
while(true){
//先判断票是否存在
if(ticket > 0){
try {
//让程序睡眠,当线程休眠的时候三个线程可能有两个多个就进来执行,让问题更清晰的出现
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第:"+ticket+"张票");
ticket--;
}
}
}
}
--------------------------------
/*
* 使用同步方法解决:
* 把访问了共享数据的代码抽取出来,放到一个方法当中
* 在方法上添加一修饰符
* 格式:
* 修饰符 synchronized 返回值类型 方法名(参数列表){
* 可能产生问题的代码(访问共享数据的代码)
* }
*
* 定义一个同步方法,同步对象也会把代码锁住,只让一个线程执行
* 同步方法锁对象 实现类对象 new RunnableImpl(),也就是this.
*
*/
//当这个类实现这个接口的时候,这就是一个多线程的类。
public class RunableImplDemoSyn implements Runnable {
//定义多个线程共享的数据
private int ticket = 100;
//设置线程任务卖票,run方法中重写要实现的功能,在其中调用payTicket方法,这个方法被synchronize进行修饰,
//就是一个同步方法,只让一个线程执行
@Override
public void run() {
System.out.println(this);
//使用死循环让代码重复执行
while(true){
//调用一下
payTicket();
}
}
//定义一个同步方法,也可生声明为static,ticket变为static即可
//静态方法优先于对象,锁对象是是本类的class对象
public synchronized void payTicket(){
if(ticket > 0){
try {
//让程序睡眠,当线程休眠的时候三个线程可能有两个多个就进来执行,让问题更清晰的出现
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第:"+ticket+"张票");
ticket--;
}
}
}
---------------------------------
/*
* 实现卖票案例:
* 解决线程安全问题
* 使用同步代码块
* 格式:
* synchronized(锁对象){
* 可能出现线程安全问题的代码(访问共享数据数据的代码)
* }
* 同步代码块中的锁对象,可以使用任意的对象
* 但是必须保证多个线程使用的锁对象是同一个
* 锁对象的作用:把同步代码块锁住,只让一个线程在同步代码块中执行
*
* 同步技术原理:
* 使用锁对象,同步锁,也叫对象锁,对象监视器
* 三个线程一起抢夺CPU的执行权,谁抢到谁执行
* 遇到同步代码块,这时会检查同步代码块是否有锁对象,发现有就会获取锁对象,进入到同步中执行
* 第二个对象进入,如果没有,就会进入阻塞状态直到第一个对象归还锁对象
* 同步中的线程,没有执行完不会释放锁对象,同步外线程没有锁进不去同步
* 程序频繁的判断锁,释放锁,会降低程序的效率。
*
*/
public class RunableImplTongBu implements Runnable {
//定义多个线程共享的数据
private int ticket = 100;
//创建一个锁对象
Object obj = new Object();
//设置线程任务卖票
@Override
public void run() {
//使用死循环让代码重复执行
while(true){
synchronized (obj) {
//先判断票是否存在
if(ticket > 0){
try {
//让程序睡眠,当线程休眠的时候三个线程可能有两个多个就进来执行,让问题更清晰的出现
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第:"+ticket+"张票");
ticket--;
}
}
}
}
}
---------------------------------
/*
* 使用线程同步技术解决线程问题
*/
public class ThreadSafeDemoSyn {
public static void main(String[] args) {
//创建一个实现类才能共享
RunableImplDemoSyn run = new RunableImplDemoSyn();
System.out.println(run);
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
//调用start开启多线程
t0.start();
t1.start();
t2.start();
}
}
---------------------------------
/*
* 使用线程同步技术解决线程问题
*
*/
public class ThreadSafeTongBu {
public static void main(String[] args) {
//创建一个实现类才能共享
RunableImplTongBu run = new RunableImplTongBu();
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
//调用start开启多线程
t0.start();
t1.start();
t2.start();
}
}