1.继承Thread类(不推荐)

代码很简单,就不说了

public class ThreadTest02 {

    public static void main(String[] args) {
new UserThread("A").start();
System.out.println("结束。。。");
} public static class UserThread extends Thread {
UserThread(String name) {
this.setName(name);
} public void run() {
System.out.println(Thread.currentThread().getName() + " run方法执行了。。。");
}
}
}

2.实现Runable接口

public class RunableTest01 {

    public static void main(String[] args) {
Thread thread = new Thread(new UserThread(), "A");
thread.start();
System.out.println("结束。。。");
} public static class UserThread implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + " run方法执行了");
}
}
}

以上运行的结果:

结束。。。
A run方法执行了

run和start的区别?

  • start()它的作用是启动一个新线程。通过start()方法来启动的新线程,处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行相应线程的run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,run方法运行结束,此线程随即终止。start()不能被重复调用。用start方法来启动线程,真正实现了多线程运行,即无需等待某个线程的run方法体代码执行完毕就直接继续执行下面的代码。这里无需等待run方法执行完毕,即可继续执行下面的代码,即进行了线程切换。
  • run()就和普通的成员方法一样,可以被重复调用。如果直接调用run方法,并不会启动新线程!程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到多线程的目的。总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。
  总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。
 

 

数据共享与非共享

1.数据不共享

新起三个不同的线程,对成员变量操作,互不影响

public class ThreadShareTest01 {

    public static void main(String[] args) {

        Thread thread1 = new Thread(new UserThread(), "A");
Thread thread2 = new Thread(new UserThread(), "B");
Thread thread3 = new Thread(new UserThread(), "C"); thread1.start();
thread2.start();
thread3.start(); } public static class UserThread extends Thread {
private int count = 10; public void run() {
while (count > 0) {
count--;
System.out.println(Thread.currentThread().getName() + " 线程过来了,count变为:" + count);
}
System.out.println("count小于0了");
}
} }

结果:

A 线程过来了,count变为:9
A 线程过来了,count变为:8
A 线程过来了,count变为:7
A 线程过来了,count变为:6
A 线程过来了,count变为:5
A 线程过来了,count变为:4
A 线程过来了,count变为:3
A 线程过来了,count变为:2
A 线程过来了,count变为:1
A 线程过来了,count变为:0
count小于0了
B 线程过来了,count变为:9
B 线程过来了,count变为:8
B 线程过来了,count变为:7
B 线程过来了,count变为:6
B 线程过来了,count变为:5
B 线程过来了,count变为:4
B 线程过来了,count变为:3
B 线程过来了,count变为:2
B 线程过来了,count变为:1
B 线程过来了,count变为:0
count小于0了
C 线程过来了,count变为:9
C 线程过来了,count变为:8
C 线程过来了,count变为:7
C 线程过来了,count变为:6
C 线程过来了,count变为:5
C 线程过来了,count变为:4
C 线程过来了,count变为:3
C 线程过来了,count变为:2
C 线程过来了,count变为:1
C 线程过来了,count变为:0
count小于0了

2.数据共享

public class ThreadShareTest02 {

    public static void main(String[] args) {

        UserThread userThread = new UserThread();

        Thread thread1 = new Thread(userThread, "A");
Thread thread2 = new Thread(userThread, "B");
Thread thread3 = new Thread(userThread, "C");
Thread thread4 = new Thread(userThread, "D");
Thread thread5 = new Thread(userThread, "E");
Thread thread6 = new Thread(userThread, "F");
Thread thread7 = new Thread(userThread, "G");
Thread thread8 = new Thread(userThread, "H");
Thread thread9 = new Thread(userThread, "I");
Thread thread10 = new Thread(userThread, "J"); thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
thread8.start();
thread9.start();
thread10.start(); } public static class UserThread extends Thread {
private int count = 10; public void run() {
count--;
System.out.println(Thread.currentThread().getName() + " 线程过来了,count变为:" + count);
}
} }

结果:

有问题了!

A 线程过来了,count变为:8
B 线程过来了,count变为:8
C 线程过来了,count变为:7
E 线程过来了,count变为:5
D 线程过来了,count变为:5
J 线程过来了,count变为:3
G 线程过来了,count变为:3
F 线程过来了,count变为:2
I 线程过来了,count变为:1
H 线程过来了,count变为:0

解决办法?

最简单的是在run方法加上synchronized,其实还有别的更高效的方法,后面会说到

        public synchronized void run() {
count--;
System.out.println(Thread.currentThread().getName() + " 线程过来了,count变为:" + count);
}

改善结果:

A 线程过来了,count变为:9
B 线程过来了,count变为:8
D 线程过来了,count变为:7
E 线程过来了,count变为:6
C 线程过来了,count变为:5
G 线程过来了,count变为:4
H 线程过来了,count变为:3
I 线程过来了,count变为:2
J 线程过来了,count变为:1
F 线程过来了,count变为:0

 ok!

 

并发编程:Thread和Runable-01的更多相关文章

  1. java 并发编程——Thread 源码重新学习

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  2. Java并发编程-Thread类的使用

    在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知识:线程的几种状态.上下文切换,然后接着 ...

  3. C++并发编程 thread

    std::thread C++11在标准库中为多线程提供组件, 使用线程需要包含头文件 thread, 其命名空间为 std. 启动新线程 每个进程至少有一个线程: 执行main()函数的线程, 其余 ...

  4. Java 并发编程:Callable和Future

    项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable实现. import java ...

  5. Java 并发编程——Callable+Future+FutureTask

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  6. Java并发编程(08):Executor线程池框架

    本文源码:GitHub·点这里 || GitEE·点这里 一.Executor框架简介 1.基础简介 Executor系统中,将线程任务提交和任务执行进行了解耦的设计,Executor有各种功能强大的 ...

  7. Java 并发编程——Executor框架和线程池原理

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  8. java并发编程——通过ReentrantLock,Condition实现银行存取款

         java.util.concurrent.locks包为锁和等待条件提供一个框架的接口和类,它不同于内置同步和监视器.该框架允许更灵活地使用锁和条件,但以更难用的语法为代价. Lock 接口 ...

  9. Java并发编程——BlockingQueue

    简介 BlockingQueue很好的解决了多线程中,如何高效安全"传输"数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利. 阻塞队列是 ...

随机推荐

  1. Asp.Net Core Identity中基于角色授权

    我们已经在之前介绍了简单的授权是在Controller或Action上添加属性Authorize来实现,那角色授权是在指定Authorize的同时指定Roles参数. 我们来看看基于角色访问的三种方式 ...

  2. 使用qt creator来编译 调试 用CMakeLists组织的工程

                                                   爱情原如树叶一样,在人忽视里绿了,在忍耐里露出蓓蕾. -- 何其芳 使用CMake作为构建系统,需要自己写 ...

  3. QT 源码分析--1

    Ref: http://blog.sina.com.cn/s/blog_6e80f1390100qoc0.html 安装qt之后(我使用的是online自动安装),安装目录下有\5.10.1\Src\ ...

  4. LeetCode 897. 递增顺序查找树(Increasing Order Search Tree)

    897. 递增顺序查找树 897. Increasing Order Search Tree 题目描述 给定一个树,按中序遍历重新排列树,使树中最左边的结点现在是树的根,并且每个结点没有左子结点,只有 ...

  5. [.Net] - 使用 iTextSharp 生成基于模板的 PDF,生成新文件并保留表单域

    背景 基于 PDF Template 预填充表单项,生成一份新的 PDF 文件,并保留表单域允许继续修改. 代码段 using iTextSharp.text.pdf; /* Code Snippet ...

  6. 介绍几款常用的在线API管理工具

    在项目开发过程中,总会涉及到接口文档的设计编写,之前使用的都是ms office工具,不够漂亮也不直观,变更频繁的话维护成本也更高,及时性也是大问题.基于这个背景,下面介绍几个常用的API管理工具,方 ...

  7. RHEL 6.5 安装Docker

    一,配置远程yum源二,下载依赖包1.安装downloadonly插件使用yum下载rpm包2.下载docker需要的依赖包三,安装docker(离线节点)1. 依次执行docker的安装包2. 启动 ...

  8. Python基础 — 八种数据类型

    Python 3.x 的八种数据类型 八种数据类型分别是: number(数字).string(字符串).Boolean(布尔值).None(空值) list(列表).tuple(元组).dict(字 ...

  9. TZOJ1299: 畅通工程

    #include<stdio.h> #include<math.h> #include<string.h> #include<algorithm> #i ...

  10. mongodb 启动及创建用户

    1. 守护进程启动,参考: https://blog.csdn.net/jj546630576/article/details/81117765 2. 用户管理参考: https://www.cnbl ...