继承Thread的方式实现多线程

public class TestThread extends Thread{
@Override
public void run() {
System.out.println("多线程运行的代码");
for(int i = 0; i < 5; i++){
System.out.println("这是多线程的逻辑代码:" + i);
}
}
}
-------------------------------
public class Test {
public static void main(String[] args) {
Thread t0 = new TestThread();// 继承Thread类的线程
t0.start();// 启动线程,开始运行run方法中的代码
System.out.println("---------------1");
System.out.println("---------------2");
System.out.println("---------------3");
//Thread t1 = new TestThread();
//t1.start();
//Thread t2 = new TestThread();
//t2.start();
}
}

解析

  • 多次运行这个main方法之后 我们发现main方法中打印的3行与开启线程运行run方法中的打印语句是混合起来
  • 而且main方法中的打印与run方法中打印语句顺序是不固定的 为什么呢?
  • main执行t0.start()方法开启多线程之后,就相当于在main方法之外开启一个支流
  • 这个个时候t0.start()的之后的main方法的其他代码的运行就与run方法运行无关了 以当前代码为例
  • t0.start()的之后的main方法的其他代码与run方法的代码并行运行 就像两条河流一样,各走各的
  • 那么控制台输出的结果就是两条并行程序的运行结果总和,这个结果需要拆开成两部分看 就可以看到,各自是保持自己输出顺序
  • 这个就是多线程的异步,这个异步相对于执行t0.start()的主程序来说的
  • 简单来说开启了线程之后run方法中运行的代码主程序中t0.start()之后的程序是并行执行的,没先后关系,这个叫异步

通过实现Runnable接口方式实现多线程

public class TestRunnable implements Runnable{

    int count = 0;
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":Runnable多线程运行的代码");
for(int i = 0; i < 5; i++){
count++;
System.out.println(Thread.currentThread().getName() + ":这是Runnable多线程的逻辑代码:" + count);
}
} }
-------------------------------
public class Test {
public static void main(String[] args) {
Thread t3 = new Thread(new TestRunnable());
t3.start();
//Thread t4 = new Thread(new TestRunnable(), "t-1");
//t4.start();
//Thread t5 = new Thread(new TestRunnable(), "t-2");
//t5.start();
Runnable run = new TestRunnable();
Thread t4 = new Thread(run, "t-1");// t-1线程名称
t4.start();
Thread t5 = new Thread(run, "t-2");
t5.start();
}
}

区别:Thread与Runnable

  • 继承Thread:线程代码存放Thread子类run方法中。重写run方法
  • 实现Runnable:线程代码存在接口的子类的run方法。实现run方法
  • 实现方法的好处
    • 避免了单继承的局限性
    • 多个线程可以共享同一个接口实现类的对象,非常适合,多个线程可以用来处理同一份资源
    • 一般使用实现接口方式来实现多线程
package day15;

public class Test1 {
public static void main(String[] args) {
TestRun run0 = new TestRun();
TestRun run1 = new TestRun(); Thread t0 = new Thread(run0); Thread t1 = new Thread(run1); t0.setName("线程t-0");// 设置线程的名称
t1.setName("线程t-1");// 设置线程的名称 t0.setPriority(1);// 设置线程的优先级
t1.setPriority(10);// 设置线程的优先级 t0.start();
t1.start();
//System.out.println(t0.getName());//如果在创建线程的时候没有指定名称,系统会给出默认名称,通过getName()获取线程名称
//System.out.println(t1.getName()); /**
* 线程的优先级,就是哪个线程有较大个概率被执行 优先级是用数组1-10表示,数字越大优先级越高,如果没有设置默认优先级是5
*/ //System.out.println("t0的优先级:" + t0.getPriority());//获取线程的优先级 System.out.println("---------------1");
System.out.println("---------------2"); System.out.println(t1.isAlive());// 判断当前的线程是否存活 t1.stop();// 强制线程生命期结束,强制停止此线程 try {
t0.join();// 相当于在这块把t0的run的代码插入到这个位置执行
/**
* 专业的说法 就是阻塞当前的main方法,先不执行System.out.println("---------------3");代码
* 先执行join进来的线程的代码
* join的线程执行完毕之后继续执行之前main方法阻塞的代码System.out.println("---------------3");
*/
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("---------------3"); System.out.println(t1.isAlive());
}
} class TestRun implements Runnable {
int count = 0; @Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":Runnable多线程运行的代码");
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);//当前线程睡眠1000毫秒
//相当于当前的这个循环每隔1000毫秒执行一次循环
} catch (InterruptedException e) {
e.printStackTrace();
} if (i % 2 == 0) {
Thread.yield();// 线程让步
} count++;
System.out.println(Thread.currentThread().getName() + ":这是Runnable多线程的逻辑代码:" + count);
}
} }

微信与支付宝支付案例

package day15;

public class Test2 {
public static void main(String[] args) {
//定义账户对象
Acount a = new Acount();
Acount a1 = new Acount(); //多线程对象
User u_weixin = new User(a, 2000);
User u_zhifubao = new User(a, 2000); Thread weixin = new Thread(u_weixin,"微信");
Thread zhifubao = new Thread(u_zhifubao,"支付宝"); weixin.start();
zhifubao.start();
}
} class Acount{
public static int money = 3000;//全局变量,所有的操作共享这个变量 /**
* 提款,判断账户钱够不够
* 多线程调用这个方法,就有问题,线程共享资源时,一个线程在执行这个方法没有完毕时,另一个线程又开始执行这个方法
* 解决思路:显然一个线程整体执行完这个方法,另一个线程再执行
* 通过synchronized同步锁来完成
* 可以直接在方法上加上synchronized关键字
* 在普通方法上加同步锁synchronized,锁的是整个对象,不是某一个方法
* 不同的对象就是不同的锁,普通方法加synchronized,线程使用不同的此方法的对象,还有共享资源的问题
*
* 普通方法加同步锁,锁的当前方法对应的对象,当前的对象的所有加了同步锁的方法是共用一个同步锁
* @param m
*/
public synchronized void drawing(int m){
String name = Thread.currentThread().getName(); if(money < m){
System.out.println(name + "操作,账户金额不足:" + money);
}else{
System.out.println(name + "操作,账户原有金额:" + money);
System.out.println(name + "操作,取款金额:" + m); System.out.println(name + "操作,取款操作:原金额" + money + " - " + "取款金额" + m);
money = money - m;
System.out.println(name + "操作,取款后的余额:" + money);
} } public synchronized void drawing1(int m){
String name = Thread.currentThread().getName(); if(money < m){
System.out.println(name + "操作,账户金额不足:" + money);
}else{
System.out.println(name + "操作,账户原有金额:" + money);
System.out.println(name + "操作,取款金额:" + m); System.out.println(name + "操作,取款操作:原金额" + money + " - " + "取款金额" + m);
money = money - m;
System.out.println(name + "操作,取款后的余额:" + money);
} } /**
* 静态的方法加synchronized,对于所有的对象都是使用同一个一个锁
* @param m
*/
public static synchronized void drawing2(int m){
String name = Thread.currentThread().getName(); if(money < m){
System.out.println(name + "操作,账户金额不足:" + money);
}else{
System.out.println(name + "操作,账户原有金额:" + money);
System.out.println(name + "操作,取款金额:" + m); System.out.println(name + "操作,取款操作:原金额" + money + " - " + "取款金额" + m);
money = money - m;
System.out.println(name + "操作,取款后的余额:" + money);
} } /**
* 对代码块加入同步锁
* 代码块synchronized(this),所有当前的对象的synchronized(this)同步的的代码都是使用同一个锁
* @param m
*/
public void drawing3(int m){
synchronized(this){//表示当前的对象的代码块被加了synchronized同步锁
//用this锁代码块是代表当前的对象,如果在其他方法中也有synchronized(this)的代码块使用的都是同一个同步锁
String name = Thread.currentThread().getName(); if(money < m){
System.out.println(name + "操作,账户金额不足:" + money);
}else{
System.out.println(name + "操作,账户原有金额:" + money);
System.out.println(name + "操作,取款金额:" + m); System.out.println(name + "操作,取款操作:原金额" + money + " - " + "取款金额" + m);
money = money - m;
System.out.println(name + "操作,取款后的余额:" + money);
}
}
} public void drawing4(int m){
synchronized(this){//表示当前的对象的代码块被加了synchronized同步锁
//用this锁代码块是代表当前的对象,如果在其他方法中也有synchronized(this)的代码块使用的都是同一个同步锁
String name = Thread.currentThread().getName(); if(money < m){
System.out.println(name + "操作,账户金额不足:" + money);
}else{
System.out.println(name + "操作,账户原有金额:" + money);
System.out.println(name + "操作,取款金额:" + m); System.out.println(name + "操作,取款操作:原金额" + money + " - " + "取款金额" + m);
money = money - m;
System.out.println(name + "操作,取款后的余额:" + money);
}
}
} /**
* synchronized修饰代码块,想要根据不同的对象有不同的锁
* synchronized(a),这个小括号中传入不同的对象就是不同的锁
* @param m
*/
public void drawing5(int m,Acount a){
synchronized(a){//表示通过方法的参数传递进来的对象的代码块被加了synchronized同步锁
//不同的对象就有不同的同步锁
String name = Thread.currentThread().getName(); //如果是微信操作的,先不执行,等支付宝操作,支付宝操作完,微信再继续操作
if(name.equals("微信")){
try {
a.wait();//当前的线程进入等待的阻塞状态
} catch (InterruptedException e) {
e.printStackTrace();
}
} if(money < m){
System.out.println(name + "操作,账户金额不足:" + money);
}else{
System.out.println(name + "操作,账户原有金额:" + money);
System.out.println(name + "操作,取款金额:" + m); System.out.println(name + "操作,取款操作:原金额" + money + " - " + "取款金额" + m);
money = money - m;
System.out.println(name + "操作,取款后的余额:" + money);
} if(name.equals("支付宝")){
try {
a.notify();//唤醒当前优先级最高的线程,进入就绪状态
// a.notifyAll();//唤醒当前所有的线程,进入就绪状态
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
} 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);
// if(Thread.currentThread().getName().equals("微信")){
//// acount.drawing(money);
// acount.drawing3(money);
// }else{
//// acount.drawing1(money);
// acount.drawing4(money);
// }
// acount.drawing2(money);//调用类的静态方法 // acount.drawing3(money); acount.drawing5(money, acount);
} }

经典生产者消费者问题

package day15;

/**
* 生产者与消费者
*
* @author lby
*
*/
public class Test3 {
public static void main(String[] args) {
Clerk c = new Clerk();
// 消费时不生产,生产时不消费 // 生产者
new Thread(new Runnable() {
@Override
public void run() {
synchronized (c) {
while (true) {// 无限循环代表无限的生产次数
if (c.productNum == 0) {// 产品数为0,开始生产
System.out.println("产品数为0,开始生产");
while (c.productNum < 4) {
c.productNum++;// 增加产品
System.out.println("库存:" + c.productNum);
}
System.out.println("产品数为" + c.productNum + ",结束生产"); c.notify();// 唤醒消费者线程
} else {
try {
c.wait();// 生产者线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}, "生产者").start(); // 消费者
new Thread(new Runnable() {
@Override
public void run() {
synchronized (c) {
while (true) {// 无限循环代表无限的消费次数
if (c.productNum == 4) {// 产品数为4,开始消费
System.out.println("产品数为4,开始消费");
while (c.productNum > 0) {
c.productNum--;// 消费产品
System.out.println("库存:" + c.productNum);
}
System.out.println("产品数为" + c.productNum + ",结束消费"); c.notify();// 唤醒生产者线程
} else {
try {
c.wait();// 消费者线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}, "消费者").start(); }
} class Clerk {
public static int productNum = 0;
}

Java-继承Thread的方式和实现Runnable接口多线程的更多相关文章

  1. Java知多少(58)线程Runnable接口和Thread类详解

    大多数情况,通过实例化一个Thread对象来创建一个线程.Java定义了两种方式: 实现Runnable 接口: 可以继承Thread类. 下面的两小节依次介绍了每一种方式. 实现Runnable接口 ...

  2. 创建线程的一般方式和匿名内部类方式对比——实现runnable接口,重新run方法

    启动:使用静态代理设计模式 优点:可同时实现继承,避免单继承局限性 一般方式: Programer.java /** * 真实角色 * * @author :liuqi * @date :2018-0 ...

  3. Java 继承Thread类和实现Runnable接口的区别

    ava中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 在实际应用中,我 ...

  4. Thread类的常用方法_sleep和创建多线程程序的第二种方式_实现Runnable接口

    sleep方法是在Thread类中的一个静态方法,当一个线程调用了sleep方法,被调用的那个线程就会暂时的让出指定时间的CPU执行权,在这段时间也不会参与CPU的调度,当时间到了之后,就会重新回到就 ...

  5. Java之多线程方式二(实现Runnable接口)

    /** * 创建多线程的方式二:实现Runnable接口 * 1. 创建一个实现了Runnable接口的类 * 2. 实现类去实现Runnable中的抽象方法:run() * 3. 创建实现类的对象 ...

  6. Android(java)学习笔记66:实现Runnable接口创建线程 和 使用Callable和Future创建线程

    1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...

  7. Android(java)学习笔记6:实现Runnable接口创建线程 和 使用Callable和Future创建线程

    1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...

  8. 50、多线程创建的三种方式之实现Runnable接口

    实现Runnable接口创建线程 使用Runnable创建线程步骤: package com.sutaoyu.Thread; //1.自定义一个类实现java.lang包下的Runnable接口 cl ...

  9. 【转载】JAVA中线程的两种实现方法-实现Runnable接口和继承Thread类

    转自: http://blog.csdn.net/sunguangran/article/details/6069317 非常感谢原作者,整理的这么详细. 在java中可有两种方式实现多线程,一种是继 ...

  10. 创建线程的两种方式:继承Thread类和实现Runnable接口

    第一种方式:继承Thread类 步骤:1.定义类继承Thread 2.覆写Threa类的run方法. 自定义代码放在run方法中,让线程运行 3.调用线程的star方法, 该线程有两个作用:启动线程, ...

随机推荐

  1. UnityShader数学基础篇

    Mathf Mathf和Math 1.Math是C#中封装好的用于数学计算的工具类,位于System命名空间中. 2.Mathf是Unity中封装好的用于数学计算的工具结构体,位于UnityEngin ...

  2. JavaScript字符串对象转JSON格式

    JavaScript字符串对象转JSON格式 原始数据                 {  xAxis: {    type: 'category',    data: ['Mon', 'Tue', ...

  3. 微信小程序校园跑腿系统怎么做,如何做,要做多久

    ​ 在这个互联网快速发展.信息爆炸的时代,人人都离不开手机,每个人都忙于各种各样的事情,大学生也一样,有忙于学习,忙于考研,忙着赚学分,忙于参加社团,当然也有忙于打游戏的(还很多),但生活中的一些琐事 ...

  4. 【C#】使用WebHttpRequest调用Restful带token接口500 返回401 未授权错误

    测试对方的接口,发现单个调用对方接口是可以的,但是多个连续的调用对方接口时,会出现第一条调用一般是200,随后的调用就会报500,401未授权的错误,除了第一条后面的请求数据几乎都不得行. 我于是用f ...

  5. CH57x/CH58x/CH59x获取从机广播信息

    有时需要通过主机设备(MCU非手机)获取从设备的广播信息例如广播包,MAC地址,扫描应答包等 以下的程序片段及功能实现是在WCH的CH59X的observer例程上实现的: 1.获取广播包 所有的函数 ...

  6. 继承,super,重写,多态,抽象,接口

    继承,super,重写,多态,抽象,接口 继承 extends 用于表示两个类之间的继承关系,继承是OOP的四大特性之一,他允许一个类(称之为子类或派送类) 继承另一个类(称之为父类或基类)的变量和方 ...

  7. 「AntV」X6 自定义vue节点(vue3)

    官方文档 本篇文档只讲解vue3中如何使用,vue2的可以参考下官方文档 安装插件 @antv/x6-vue-shape 添加vue组件 既然使用vue节点,那么我们就需要准备一个vue的组件,这个组 ...

  8. Web 网页性能及性能优化

    Web 网页性能及性能优化 一.Web 性能 Web 性能是 Web 开发的一个重要方面,侧重于网页加载速度以及对用户输入的响应速度 通过优化网站来改善性能,可以在为用户提供更好的体验 网页性能既广泛 ...

  9. rsync备份

    备份工具rsync 备份是太常见.且太重要的一个日常工作了. 备份源码.文档.数据库.等等. 类似cp命令拷贝,但是支持服务器之间的网络拷贝,且保证安全性. 学习背景 超哥游戏公司要每天都要对代码备份 ...

  10. Big Exponential Addition

    Big Exponential Addition 给定一非负整数n计算2^n的值,一般而言把 2 乘上 n 次,就能得到答案.然而,当n特别大时,2^n要一次次地乘2可能稍嫌太慢,面对此一巨大问题利用 ...