JAVA基础之JAVA线程

1.什么是线程?

在Java编程思想第四版中是这样定义的:利用对象,可将一个程序封装为互相独立的区域,我们通常也需要将一个程序转化为多个独立运行的子任务。这样的每个子任务叫做一个“线程”。在编写程序时,可将每个线程都想像为独立运行,而且都有自己的CPU。

2.什么是进程?

进程是指一种“自包容”运行程序,有自己的地址空间,“多任务”操作能同时运行多个进程(程序),但实际由于CPU分时机制的作用,使每个CPU都能循环获取自己的CPU时间片。由于轮换速度非常快,使所有的程序像是在同时进行一样。线程是进程内部单一的一个顺序控制流,因此,一个进程可能容纳了多个同时执行的线程。

3.实现线程的两种方式

3.1 继承Thread类

java有多个线程但是只有一种Thread类
Thread是个表示线程的类,它有着启动线程,连接线程,让线程闲置等方法…

当有超过一个以上的执行空间时,看起来像是有好几件事在同时发生,只有多处理器系统才能做到,使用java可以让他看起来像是同时在执行,但是实际上只是在执行空间中快速的切换,因此才会感觉每项任务都在同时执行
TestThred 类继承了Thread

public class TestThred extends Thread{
    @Override
    public void run() {
    //一般一个线程的任务就会写在这里面
        for (int i =0;i<5;i++){
            System.out.println("业务逻辑:"+i);
        }
    }
}
public class Test {
    public static void main(String[] args){
        Thread t1 = new TestThred();
        System.out.println("开启多线程咯~");
        t1.start();
        System.out.println("=============1===================");
        System.out.println("=============2===================");
        System.out.println("=============3===================");

    }
}

在以上代码中:
1.Thread t1 = new TestThred();表示创建了Thread实例,但是还没启动,也就是说,有Thread对象,没有执行中的线程
2.t1.start():表示变成了可执行状态,只要轮到她了就可以执行了,该线程已经布置好了空间
3.之后就靠java虚拟机线程调度机制来决定了

一旦线程进入了可执行状态,他会在可执行和执行中两种状态中来来去去,同时也有另外一种状态:暂时不可执行,也叫被堵塞状态

以下是上面代码的几次运行结果:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
从运行结果可以看出,main方法中的打印与run()方法的打印语句的执行顺序是不固定的,那么从这里就可以看出:
当main执行start()之后,mian方法的其它代码就与run()里的代码并行了,就像是一条河流的两个分支那样并行前进。各走各的,互不影响。这其实是由于线程调度器的作用

3.2 实现Runnable接口

测试代码:

public class TestRunnable implements Runnable {
    @Override
    public void run() {
        //Thread.currentThread().getName()是获取到线程的名字,可有可无
        System.out.println(Thread.currentThread().getName()+"代码逻辑");
        for (int i =0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+"线程的业务逻辑:"+i);
        }
    }
}
public class Test {
    public static void main(String[] args){
        Thread t1 = new Thread(new TestRunnable(),"线程一");
        t1.start();
        System.out.println("=============1===================");
        System.out.println("=============2===================");
        System.out.println("=============3===================");

    }
}

在这里插入图片描述在这里插入图片描述
和继承了Thread的执行效果是一样的,每次保证自己线程内的执行顺序一样,新开线程相对于main()方法的执行是异步的,互不影响。

3.3 线程调度器

线程调度器会决定哪个线程从等待的状态中挑出来运行以及何时送回等待状态。他会决定哪个线程要运行多久,当线程被踢出时,调度器也会指定线程要回去等待下一次机会或者是堵塞。并且没有API可以控制调度器,调度无法确定,可以用setPriority()来设置线程的优先级,但是只是提高概率,不能百分百改变!但是有sleep的存在,可以让指定的线程“睡”指定的时间,在“睡觉”时间内线程肯定是不会运行的,其它的就无法保证。

3.4继承方式和实现方式的区别

3.4.1 区别

继承Thread:线程代码存放于Thread子类的run方法中(重写)
实现Runnable:线程代码存放于接口子类的run方法中(实现)

3.4.2 实现方法的好处

两种方法一般使用实现的方法来实现多线程:
1.避免了单继承的局限性
2.多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源
例:

public class TestRunnable implements Runnable {
	//被两个线程共享的资源
    int count = 0;
    @Override
    public void run() {
        //Thread.currentThread().getName()是获取到线程的名字,可有可无
        System.out.println(Thread.currentThread().getName()+"代码逻辑");
        for (int i =0;i<5;i++){
            count ++;
            System.out.println(Thread.currentThread().getName()+"线程的业务逻辑:"+count);
        }
    }
}

测试代码:

public class Test {
    public static void main(String[] args){
        Runnable runnable = new TestRunnable();
        Thread t1 = new Thread(runnable,"线程一");
        t1.start();
        Thread t2 = new Thread(runnable,"线程二");
        t2.start();
        System.out.println("=============1===================");
        System.out.println("=============2===================");
        System.out.println("=============3===================");

    }
}

运行结果:
在这里插入图片描述

4 线程的生命周期

截图来源:求知课堂
在这里插入图片描述
线程的完整生命周期经历了五个状态:
1.新建:当一个Thread类或其子类的对象被声明并创建的时候,新的线程对象处于新建状态
2.就绪:处于新建状态的线程被start()之后,进入线程队列等待CPU时间片,此时具备了运行条件
3.运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态,run()方法定义了线程的操作和功能
4.阻塞:在某种特殊情况下,被认为挂起或执行输入输出操作时,让出CPU并临时终止自己的执行,进入阻塞状态
5.死亡:线程完成了他的全部工作或者被强行终止

5 线程的同步和死锁

我们先来分析一下这个场景:
小王和小红对同一个账户(内有3000元)同时进行取钱操作,各取2000元,这样操作是有可能会出现负数钱的:

public class TestSynchronized {
    public static void main(String[] args){
        Acount acount = new Acount();
        //多线程对象
        User u_xiaohong =new User(acount,2000);
        User u_xiaowang =new User(acount,2000);
        Thread xiaohong = new Thread(u_xiaohong,"小红");
        Thread xiaowang = new Thread(u_xiaowang,"小王");
        xiaohong.start();
        xiaowang.start();
    }
}

/**
 * 进行取钱操作
 */
class Acount{
    public static int money = 3000;
    public void drawing(int m){
        //操作者的名字
        String name = Thread.currentThread().getName();
        //取钱之前加一个判断,如果钱不够的话不给取
        if (money<m){
            System.out.println(name+"操作,余额不足~");
        }else {
            System.out.println(name + "操作,原有账号有" + money + "块钱~");
            System.out.println(name + "操作,取款金额" + m);
            money = money - m;
            System.out.println(name + "操作,余额" + money);
        }
    }

}

/**
 * 用户操作
 */
class User implements Runnable{
    Acount acount;
    int money;
    public User(Acount acount,int money){
        this.acount = acount;
        this.money = money;
    }
    @Override
    public void run() {
        //取钱
        acount.drawing(money);
    }
}

运行结果:

在这里插入图片描述
我们可以看到,就算是在取钱之前加了一个判断,但是使用多线程的方法去取钱的话,判断就起不了作用,因为线程在共享资源时,一个线程还没执行完毕的时候,另一个线程就开始执行,会导致读取到的共享资源有问题。

解决方法:
对于多条操作共享数据语句时,只能让一个线程都执行完,在执行过程中,其它线程都不可以执行。
即在取钱操作的时候加上同步锁:可以直接在方法上面加
在这里插入图片描述运行结果:
在这里插入图片描述

注意:加普通方法上加synchronized操作的是对象,而不是普通方法。

参考书籍资料:《Java编程思想》 第四版;《Head First Java》;求知课堂网络视频

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
使用 JavaScript 编写的 Squareshooter 游戏及其源代码   项目:使用 JavaScript 编写的 Squareshooter 游戏(附源代码) 这款游戏是双人游戏。这是一款使用 JavaScript 编写的射击游戏,带有门户和强化道具。在这里,每个玩家都必须控制方形盒子(作为射手)。这款射击游戏的主要目标是射击对手玩家以求生存。当它射击对手时,它会获得一分。 游戏制作 该游戏仅使用 HTML 和 JavaScript 开发。该游戏的 PC 控制也很简单。 对于玩家 1: T:朝你上次动作的方向射击 A:向左移动 D:向右移动 W:向上移动 S:向下移动 对于玩家2: L:朝你上次移动的方向射击 左箭头:向左移动 右箭头:向右移动 向上箭头:向上移动 向下箭头:向下移动 游戏会一直进行,直到您成功射击对手或对手射击您为止。游戏得分显示在顶部。所有游戏功能均由 JavaScript 设置,而布局和其他次要功能则由 HTML 设置。 如何运行该项目? 要运行此项目,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox。要运行此游戏,首先,通过单击 index.html 文件在浏览器中打开项目。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值