0826总结
疑问
while 的条件里一定是“true”吗?
如下面的两段代码都可以完成作业题2,并且第二种方法当执行完,我们获得想要的结果后可以自动退出运行,第一种还要手动点击停止运行的按钮。
while (true){
if (i%2==1&&i<=200){
System.out.println(Thread.currentThread().getName()+"---"+i);
}
i++;
}
while (i<=200){
if (i%2==1){
System.out.println(Thread.currentThread().getName()+"---"+i);
}
i++;
}
知识点
几个概念
并发:在同一个时间段执行两个或者是多个操作 (交替执行)【一人吃两个馒头】
并行:在同一个时刻执行两个或者是多个操作【两个人吃两个馒头】
进程: 正在运行程序,在内存里开辟过空间(任务管理器《ctrl + alt + delete》里面的)
线程:表示每一条执行的路径(如360杀毒里面的 扫描、垃圾清理、修复漏洞同时进行)
进程与线程的关系:一个进程里可以有多个线程,但是一个线程只能存在一个进程里面。
线程分配情况
1、按照时间均匀的分配:两个线程交替执行,以时间为标准(该方式不存在 )
2、抢占式分配:任意一个线程,谁能够抢到cpu的资源谁就执行(在Java里面就是这种方式)
只执行main 方法:属于单线程,从上到下执行(Java里支持多线程)
实现多线程的方式
1、继承线程类
Thread 类:Java 虚拟机允许应用程序并发地运行多个执行线程
实现的步骤:
1、创建一个Thread 的子类
2、重写 run() 方法 【run方法也就是子线程要执行的操作】
3、实例化这个子类
4、调用 start() 开启线程
//1、2步
public class MyThread extends Thread {
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
//3、4步
MyThread thread=new MyThread();
thread.start(); // 只有调用这个方法才会去开辟一条新的路径
注意点
一个线程只能够开启一次,重复开启会产生错误(java.lang.IllegalThreadStateException)
2、实现 Runnable 接口类(常用)
实现的步骤:
1、定义一个类来实现这个接口
2、实现 run() 方法
3、实例化这个实现类
4、实例化一个Thread,传递参数,参数是这个实现类
5、调用 start() 方法
//1、2步
public class Runable implements Runnable {
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
//3-5步
public static void main(String[] args) {
Runable runable=new Runable();
Thread thread=new Thread(runable);
thread.start();
}
好处:
1、解决Java单继承的问题
2、可扩展性增强,实现申明与调用的分离,降低了耦合度
3、继承 Thread 实现了这个接口
实现多线程的效率:
对于整个系统来说,效率是提高,但是对于具体的某一个线程,效率就是降低
3、使用类名内部来实现多线程
第一种:Thread thread = new Thread(new Runnable() {}
第二种:Runnable runnable = new Runnable() {}
线程中的一些方法
返回对当前正在执行的线程对象的引用(也就是当前线程):currentThread()
获取线程的名称:getName()
设置线程的名称:setName(String name)【一定要在开启线程之前进行设置,可以通过构造的方式来设置线程的名称】
让当前线程睡一会(停止),别的线程可以执行了:sleep(long millis)
设置线程的优先级:setPriority(int newPriority)【最小是1 默认是5 最大是10,注意:设置优先级不一定是最先执行,只是优先执行的机遇更大一点】
join():如果有两个线程: A线程 调用了join方法, A线程执行完成之后,B线程才能执行
注意:1、这个方法必须在线程开启之后进行调用;2、这个方法底层还是调用了wait()方法
礼让:yield(); 如果有两个线程: A线程 调用了yield()方法,b线程不一定就会执行
守护线程:setDaemon(boolean on); 如果有两个线程: A是被守护线程,B守护线程; 如果A终止了,B线程也会终止
判断其是否为守护线程:isDaemon()
避免多线程同时抢占资源的方案
1、同步代码块
关键字:synchronized
语法:synchronized (){}
() 跟的是对象(这个对象可以是任意的对象)
{} 跟的是会出现共享数据问题的代码
synchronized (obj){
if (count>0){
System.out.println(Thread.currentThread().getName()+"\t"+"购买了第"+count+"张票");
count--;
}
}
注意:三个对象必须是这个锁对象(锁对象:保证只有一个线程进入)
2、同步方法
步骤:
1、把可能出现数据问题的代码抽取成一个方法
2、给方法加上锁的关键字
@Override
public void run() {
show(); //同上1
}
3、使用Lock
Lock 是一个接口,实现并提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作;此实现允许更灵活的结构
常规的两个方法:
获取锁:lock()
释放锁:unlock()
步骤:
1、实例化这个对象
2、在同步可以出现数据异常的头部调用其lock()
3、在同步可以出现数据异常的尾部加上 unlock() (不常用)
@Override
public void run() {
while (true){
try {
l.lock();
if (count>0){
System.out.println(Thread.currentThread().getName()+"\t"+"购买了第"+count+"张票");
count--;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
l.unlock();
}
}
}