Thread类的常用方法----多线程基础练习
创建多线程程序的第一种方式----继承Thread类
常用API
构造方法
public Thread() :分配一个新的线程对象。
public Thread(String name) :分配一个指定名字的新的线程对象。
public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。
常用方法
public String getName() :获取当前线程名称。
public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run() :此线程要执行的任务在此处定义代码。
public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
获取线程的名称
继承Thread类重写run方法。
/**
* 获取线程的名称
* 1:使用Thread类中的方法getName()
* String getName() //放回当前线程的名称
* 2:先获得当前执行的线程,使用线程中的getName()方法返回线程的名称
* static Thread currentThread() //返回当前正在执行的线程
*/
public class myThread extends Thread {
@Override
public void run() {
System.out.println(getName());
System.out.println(currentThread().getName());
}
}
主线程
public class Main {
public static void main(String[] args) {
myThread thread = new myThread();
thread.start();
new myThread().start();
new myThread().start();
}
}
效果
设置线程的名称
继承Thread类重写run方法。
/**
* 设置线程的名字
* 1:setName("线程名字")
* 2:使用带参数的构造方法::创建一个带参数的构造方法,参数传递线程的名称;调用父类带参构造方法,让父类(Thread)给子线程起一个名字。
*/
public class myThread extends Thread {
public myThread(){}
public myThread(String name){
super(name);
}
@Override
public void run() {
System.out.println(getName());
}
}
主线程
public class Main {
public static void main(String[] args) {
myThread thread = new myThread();
thread.setName("zhang");
thread.start();
myThread thread2 = new myThread("guang");
thread2.start();
}
}
效果
Sleep方法
继承Thread类重写run方法。
/**
* public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
* 毫秒结束后线程继续执行
*/
public class myThread extends Thread {
@Override
public void run() {
System.out.println("1");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(2);
}
}
主线程
public class Main {
public static void main(String[] args) {
myThread thread = new myThread();
thread.start();
System.out.println(".....");
}
}
效果
实现多线程的第二种方式----实现Runnable接口 java.lang.Runnable
介绍
- 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
- 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正
的线程对象。 - 调用线程对象的start()方法来启动线程。
通过Runnable接口创建多线程
/**
* 创建多线程的第二种方式,实现Runnable接口
* java.lang.runnable
* Runnable接口应该由那些通过某一线程执行其实例的类来实现。其实例的类必须定义一个称为run的无参数方法
* java.lang.Thread类的构造方法
* Thread(Runnable target) 分配新的 Thread 对象。
* Thread(Runnable target, String name) 分配新的 Thread 对象。
* 实现步骤:
* 1、创建一个Runnable接口的实现类
* 2、在实现类中重写Runnable接口的run方法,设置线程任务
* 3、创建一个Runnable接口的实现类对象
* 4、创建Thread类对象,构造方法中传递Runnable接口的实现类对象
* 5、调用Thread类中的start方法,开启新的线程执行run方法
*/
public class myThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class Main {
public static void main(String[] args) {
myThread th = new myThread();
Thread thread = new Thread(th);
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
效果
继承Thread和实现Runnable接口的区别
实现Runnable接口比继承Thread类所具有的优势:
- 适合多个相同的程序代码的线程去共享同一个资源。
- 可以避免java中的单继承的局限性。
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
- 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
匿名内部类实现线程的创建
使用线程的内匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作。
/**
* 匿名内部类方式实现线程的创建
*
* 匿名:没有名字
* 内部类:写在其他类内部的类
*
* 匿名内部类作用:简化代码
* 把子类继承父类,重写父类的方法,创建子类对象合一步完成
* 把实现类实现接口,重写接口中的方法,创建实现类兑现合成一步完成
* 匿名内部类的最终产物:子类/实现类对象,而这个类没有名字
*
* 格式
* new 父类/接口(){
* 重写父类/接口中的方法
* }
*/
public class Main {
public static void main(String[] args) {
//使用Thread类创建
new Thread(){
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}.start();
//使用Runnable接口创建
Runnable r = new Runnable(){
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
};
new Thread(r).start();
//优化Runnable接口方式
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}).start();
//主线程
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
效果
线程安全问题
多线程访问了共享数据,会产生线程安全问题
线程不安全案例
/**
* 卖票案例,三个线程同时卖票
*/
public class RunnableImp implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"售出了"+ticket+"号票");
ticket--;
}
}
}
}
public class Main {
public static void main(String[] args) {
RunnableImp runnableImp = new RunnableImp();
new Thread(runnableImp).start();
new Thread(runnableImp).start();
}
}
效果
发现程序出现了两个问题:
- 相同的票数,比如5这张票被卖了两回。
- 不存在的票,比如0票与-1票,是不存在的。
这种问题,几个窗口(线程)票数不同步了,这种问题称为线程不安全。
当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。
要解决上述多线程并发访问一个资源的安全性问题:也就是解决重复票与不存在票问题,Java中提供了同步机制
(synchronized)来解决。
java中有三种方式实现同步操作 - 同步代码块。
- 同步方法。
- 锁机制。
第一种解决方式----同步代码块
同步代码块: synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
格式
synchronized(同步锁){
需要同步操作的代码
}
同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.
- 锁对象 可以是任意类型。
- 多个线程对象 要使用同一把锁。
案例
/**
* 出现了线程安全问题,卖出了重复的和不存在的票
*
* 解决线程安全的一种方式:使用同步代码块
* 格式:
* synchronized(锁对象){
* 可能会出现线程安全问题的代码
* }
*/
public class RunnableImp implements Runnable {
private int ticket = 100;
//创建一个锁对象,,随便一个对象
Object object = new Object();
@Override
public void run() {
while (true){
//锁对象只有一个,每次运行时一个线程执行会拿走锁对象,其他线程到了,如果没有锁则进入阻塞状态
synchronized (object){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"售出了"+ticket+"号票");
ticket--;
}
}
}
}
}
public class Main {
public static void main(String[] args) {
RunnableImp runnableImp = new RunnableImp();
new Thread(runnableImp).start();
new Thread(runnableImp).start();
}
}
效果
第二种方式----同步方法
同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外
等着。
格式
public synchronized void method(){
可能会产生线程安全问题的代码
}
/**
* 卖票案例出现了线程安全问题
* 卖出了不存在的票和重复的票
*
* 解决线程安全问题的第二种方案:使用同步方法
* 使用步骤:
* 1、把访问量共享数据的代码抽取出来,放到一个方法中
* 2、在方法上添加synchronized修饰符
*/
public class RunnableImp implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true){
payTiclet();
}
}
public synchronized void payTiclet(){
if(ticket>0){
try {
//线程休眠,效果更明显
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"售出了"+ticket+"号票");
ticket--;
}
}
}
public class Main {
public static void main(String[] args) {
RunnableImp runnableImp = new RunnableImp();
new Thread(runnableImp).start();
new Thread(runnableImp).start();
new Thread(runnableImp).start();
}
}
效果
同步锁是谁?
对于非static方法,同步锁就是this。
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。class文件对象
第三种方式----Lock锁
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,
同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。
Lock锁也称同步锁,加锁与释放锁方法化了,如下:
public void lock() :加同步锁。
public void unlock() :释放同步锁。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class RunnableImp implements Runnable {
private int ticket = 100;
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();//在可能出现线程安全问题的代码前打开锁
if(ticket>0) {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "售出了" + ticket + "号票");
ticket--;
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();//放在finally中一定会关掉锁
}
}
}
}
public class Main {
public static void main(String[] args) {
RunnableImp runnableImp = new RunnableImp();
new Thread(runnableImp).start();
new Thread(runnableImp).start();
new Thread(runnableImp).start();
}
}
Thread类的常用方法----多线程基础练习的更多相关文章
- 创建多线程的方式&Thread类的常用方法
创建多线程的第一种方式:继承java.lang.Thread类 注意:1.一个线程只能执行一次start() 2.不能通过Thread实现类对象的 run()去启动一个线程 3.增加加一个线程,需要新 ...
- 多线程——继承Thread类实现一个多线程
继承Thread类实现一个多线程 Thread类部分源码: package java.lang; //该类实现了Runnable接口 public class Thread implements Ru ...
- Thread类的常用方法_获取线程名称的方法和设置线程名称的方法
Thread类的常用方法 获取线程的名称: 1.使用Thread类中的方法getName() String getName() 返回该线程的名称 2.可以先获取到当前正在执行的线程,使用线程中的方法g ...
- Thread类的常用方法_sleep和创建多线程程序的第二种方式_实现Runnable接口
sleep方法是在Thread类中的一个静态方法,当一个线程调用了sleep方法,被调用的那个线程就会暂时的让出指定时间的CPU执行权,在这段时间也不会参与CPU的调度,当时间到了之后,就会重新回到就 ...
- Thread类的常用方法_sleep和创建多线程程序的第二种方式实现Runnable接口
public static void sleep(long millis);//使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行). 毫秒数结束后线程继续执行 package com.yang.T ...
- Thread类的常用方法_获取线程名称的方法和Thread类的常用方法_设置线程名称的方法
构造方法: public Thread();分配一个新的线程对象 public Thread(String name);分配一个指定名字的新的线程对象 public Thread(Runnable t ...
- Thread类详解 多线程中篇(二)
Java.lang.Thread是Java应用程序员对Java多线程的第一站,Thread就是对Java线程本身的抽象 所以在Java中的线程编程概念中,一个Thread实例 == 一个线程 线程有哪 ...
- Thread类的常用方法
String getName() 返回该线程的名称. void setName(String name) 改变线程名称,使之与参数 name 相同. int getPriority() 返回线程的优先 ...
- 通过继承Thread类来创建多线程 关键词 start
// 代码 public class MyThread extends Thread { public void run(){ for(int i=0;i<10;i++){ try { Thre ...
随机推荐
- File类与常用IO流第八章——缓冲流
第八章.缓冲流 缓冲流概述 缓冲流,也叫高效流,是对4个基本的FileXxx流的增强.按照数据类型分为4类: 输入缓冲流 输出缓冲流 字节缓冲流 BufferedInputStream Buffe ...
- Java基础之反射总结
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...
- Requests方法 -- 关联用例执行
1.参照此篇流程 :Requsts方法 -- Blog流程类进行关联 2.用例接口目录如下: 3.用例代码如下: import requestsimport unittestfrom Request. ...
- 6 Java基础整理 第六-八章
1.封装 封装的目的是简化编程和增强安全性. 简化编程是指,封装可以让使用者不必了解具体类的内部实现细节,而只是要通过提供给外部访问的方法来访问类中的属性和方法 增强安全性是指,封装可以使某个属性只能 ...
- dos命令的学习
打开CMD的方式 开始+系统+命令提示符 Windows+R+输入CMD 在任意的文件夹下面,按住shift+点击鼠标右键,在此处打开命令行窗口 资源管理器的地址栏前面加上CMD路径 管理员方式运行: ...
- informix常用函数
一.常用函数 1.decimal decimal(14,2):14位数,小数占两位:decimal(26,8),有效长度为26,小数位占8位. 2.cast cast:Oracle中的数据类型转换函数 ...
- Deepin 20.2.2 /UOS 20.2 添加ppa源
由于 工作需要,需要通过PPA安装一些优质的软件包,但是 Deepin 默认不支持PPA源 解决方法 由于Deepin/Uos系统默认是没有安装PPA的那么我们得先安装PPA来支持"add- ...
- 开源低代码平台开发实践二:从 0 构建一个基于 ER 图的低代码后端
前后端分离了! 第一次知道这个事情的时候,内心是困惑的. 前端都出去搞 SPA,SEO 们同意吗? 后来,SSR 来了. 他说:"SEO 们同意了!" 任何人的反对,都没用了,时代 ...
- Java的三种日期工具 Date Calendar SimpleDateFormat
三种日期工具 配合下面的案例可以更加深度的了解 Date 需要导包java.util.Date Date d = new Date(); //两种都是获取到现在时间的时间戳 long t1 = d.g ...
- Arp欺骗和DNS投毒
中间人攻击 ARP缓存攻击 ARP(Address Resolution Protocol,地址解析协议)是一个位于TCP/IP协议栈中的网络层,负责将某个IP地址解析成对应的MAC地址.简单来说,就 ...