*多线程:多任务同时执行 ,如果需要多线程才使用,不需要无需使用
* 优点:提高效率,完善功能
* 缺点:开发复杂,可能出现不安全情况
* 线程 和 进程的区别
* 1.每个进程都有自己独立的代码和数据空间,内存空间
* 2.一类线程共享进程的资源
* 3.一个进程包含一到多个线程
* 4.进程是资源分配的最小单位
* 5.线程是cpu调度的最小单位
*
* 多线程的创建方式:
* 1.继承Thread类,重写run()方法 + start()开启多线程
* 2.实现Runnable接口,重写run()方法 --推荐
* 1)避免单继承的局限性
* 2)实现资源共享
* 3.实现 Callable接口,重写call方法
* 1)使用麻烦
* 2)抛出异常,具有返回值
public class ThreadDemo01 extends Thread {
/*
* 定义要执行的线程体
*/
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.println("一边陪女朋友...");
}
}
public static void main(String[] args) {
ThreadDemo01 th=new ThreadDemo01(); //创建多线程
th.start(); //开启多线程 等待cpu分配时间片,调用线程的执行
//th.run(); //单线程,方法的调用,执行完毕run()方法,才能继续执行main方法的代码
for(int i=0;i<20;i++){
System.out.println("一边敲代码.....");
}
//th.start(); 是多线程的开启,但是没有切换执行费的效果
}
}
2.实现Runnable接口,重写run()方法 --推荐
* 1)避免单继承的局限性
* 2)实现资源共享
重写方法异常问题:
* 如果父类方法没有抛出异常,子类重写方法就不能抛出异常
* 如果父类方法有抛出异常,子类方法抛出异常<=父类
使用内部类,匿名内部类,Lambda表达式的形式开启线程
public class ThreadDemo06 {
//静态内部类
static class Inner1 extends Thread{
@Override
public void run() {
for(int i=0;i<=20;i++){
System.out.println("hahahha"+i);
}
}
}
public static void main(String[] args) {
//局部内部类
class Inner2 extends Thread{
@Override
public void run() {
for(int i=0;i<=20;i++){
try {
Thread.sleep(20);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("heheheh"+i);
}
}
}
//静态内部类
new Inner1().start();
new Inner2().start();
//匿名内部类
new Thread(new Runnable(){
@Override
public void run() {
for(int i=0;i<=20;i++){
try {
Thread.sleep(20);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("heiheihei"+i);
}
}
}).start();
//Lambda表达式
new Thread(()->{
for(int i=0;i<=20;i++){
try {
Thread.sleep(20);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("xixixixi"+i);
}
}).start();
}
}
线程的状态
* 新生 :new Thread(),创建一个线程
* 就绪 :start(),就绪不是运行,就绪状态的线程会处于就绪队列中,等待cpu的调度
* 运行 :当cpu为某个现成饭非配时间片,这个线程开始执行
* 阻塞 :sleep(),阻止线程的正常执行,等待阻塞解除
* 终止 :线程结束
* 注意:
* 1.如果一个线程一旦终止,没有办法恢复,就算重新开启也不是原来的线程
* 2.阻塞状态接触,没有办法直接恢复运行状态,都会进入就绪状态
* 如何使线程进入到终止状态:
* 1.执行执行完毕 2.通过外部干涉 1)调用stop() destroy() 2)通过外部标识判断**
* 如何使线程进入到就绪状态:
* 1.start()
* 2.阻塞状态接触直接进入就绪状态
* 3.yield() 礼让线程
* 4.线程切换,被切换的线程直接进入就绪状态
* 如何使线程进入到阻塞状态:
* 1.sleep()
* 2.join() 插队
* 3.wait()
* 4.IO操作
*sleep(毫秒数) 线程睡眠,静态方法
* 可以方法问题发生的可能性
* 模拟网络延时
* 使程序进入阻塞状态,让出cpu的资源,如果遇到对象锁的情况,sleep()抱着对象资源睡觉,不会释放对象的锁
*/ yield() 礼让线程 高风亮节 静态方法
* 可以放大对方执行的可能性
join()合并线程 插队线程
* 爸爸让儿子去买烟...
线程的状态getState() 返回枚举类型的状态信息
* 优先级: 提高|降低可能性,不能去决定性作用
* 1~10之间的数字表示线程的优先级 1最小 10最大 默认是5
* staticintMAX_PRIORITY
线程可以具有的最高优先级。
staticintMIN_PRIORITY
线程可以具有的最低优先级。
staticintNORM_PRIORITY
分配给线程的默认优先级。
* setPriority()设置线程的优先级别
* getPriority()获取线程的优先级别
线程安全问题:
* 多个线程,同时操作同一个资源的时候,有可能出现线程不安全的问题
* synchronized 同步锁
* 同步方法 :方法上添加synchronized
* 成员方法
* 静态方法:锁静态方法相当于锁类
* 同步块:
* synchronized(this|类名.class|资源){...}
* this:对象
* 类名.class:类
* 资源:成员变量
* 注意:
* 锁的范围太大,效率低,锁的范围太小,锁不住
* 锁一定要锁不变的内容,变的锁不住,自定义的引用数据类型的对象地址
*
* 单例模式
* 懒汉式:线程不安全的
* 双重检查:double check :提高效率,把锁的范围控制在相对来说最小
/*
* 12306案例 线程不安全问题处理1:
* 锁方法范围太大,效率太低,但是较简单
*/
public class Web12306_02 implements Runnable{
//共享的资源 100张票
int tickets=100;
// A B C
@Override
public void run() {
//循环买票
while(true){
if(test()){
break;
}
}
}
//定义一个方法,每次循环要执行的代码
//返回值: true,没票了结束购买 false->继续购买
public synchronized boolean test(){
if(tickets<=0){
return true;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
} //执行到这个方法,就休息200ms
System.out.println(Thread.currentThread().getName()+"正在买"+tickets--+"张票");
return false;
}
public static void main(String[] args) {
Web12306_02 web=new Web12306_02(); //资源---每一个线程执行的线程体都是Web12306_03类中的代码run
//创建线程
new Thread(web,"武国伟").start();
new Thread(web,"魏中华").start();
new Thread(web,"李啸").start();
}
}
12306案例 线程不安全问题处理2:
* 锁块:锁资源:一般指成员属性
* 资源只能是引用数据类型
* 一定要锁不变的内容
*
*/
public class Web12306_03 implements Runnable{
//共享的资源 100张票
Ticket tickets=new Ticket(); //一个对象中100张票
@Override
public void run() {
//循环买票
while(true){
synchronized (tickets) { //锁的对象的地址
if(tickets.num<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {} //执行到这个方法,就休息200ms
System.out.println(Thread.currentThread().getName()+"正在买"+tickets.num--+"张票");
}
}
}
public static void main(String[] args) {
Web12306_03 web=new Web12306_03(); //资源---每一个线程执行的线程体都是Web12306_03类中的代码run
//创建线程
new Thread(web,"武国伟").start();
new Thread(web,"魏中华").start();
new Thread(web,"李啸").start();
}
}
class Ticket{
int num=100;
}
* 12306案例 线程不安全问题处理2:
* 锁块: this:所对象-->指代当前调用成员方法的对象
* 如果对象中存在多个资源,相当于把一整个对象的所有资源全部锁住了
* 如果只需要锁对象中的某个资源,提高效率,可以只锁资源
*/
public class Web12306_04 implements Runnable{
//共享的资源 100张票
int tickets=100;
@Override
public void run() {
//循环买票
while(true){
// synchronized (this) { //同步快中的代码执行完毕才会释放对象锁
if(tickets<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {} //执行到这个方法,就休息200ms
System.out.println(Thread.currentThread().getName()+"正在买"+tickets--+"张票");
// }
}
}
public static void main(String[] args) {
Web12306_04 web=new Web12306_04(); //资源---每一个线程执行的线程体都是Web12306_03类中的代码run
//创建线程
new Thread(web,"武国伟").start();
new Thread(web,"魏中华").start();
new Thread(web,"李啸").start();
}
}