java多线程买东西代码_Java多线程代码详解

本文详细介绍了Java中多线程的创建,包括继承Thread类和实现Runnable接口两种方式,并通过实例展示了线程安全问题及解决方案,如同步机制、Lock锁以及Callable接口。此外,还提到了线程池的使用及其优势。
摘要由CSDN通过智能技术生成

自学JavaDay14

多线程

多线程的创建

package com.th1024.multiplethreads.ThreadDemo;

/**

* 多线程的创建

*

* 方式一:继承于Tread类

* 1. 创建一个继承于Thread类的子类

* 2. 重写Thread类中的run()方法

* 3. 创建Thread类的子类的对象

* 4. 通过此对象调用start()

* 例子:遍历100以内的所有偶数

*

* 方式二:实现Runnable接口--开发中优先选择

* 1. 定义子类,实现Runnable接口

* 2. 子类中重写Runnable接口中的run方法

* 3. 通过Thread类含参构造器创建线程对象

* 4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中

* 5. 调用Thread类的start方法:开启线程,调用Runnable子类接口中的run方法

* 优点:

* 1. 避免了单继承的局限性

* 2. 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源

*

* @author TuHong

* @create 2021-01-23 14:05

*/

public class ThreadTest {

public static void main(String[] args) {

//3. 创建Thread类的子类的对象

MyThread1 t1 = new MyThread1();

//4. 通过此对象调用start()--分线程执行run()方法

t1.start();

// t1.run();//只是在主线程调用run方法

//启动其他线程,不能通过已经start()的线程去执行

// t1.start();//异常---IllegalThreadStateException

//需重新创建一个线程的对象

// MyThread1 t2 = new MyThread1();

// t2.start();

//主线程

for (int i = 0; i < 100; i++) {

if(i % 2 != 0){

System.out.println(Thread.currentThread().getName() + ":" + i);

}

}

//3. 通过Thread类含参构造器创建线程对象

//4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中

MyThread2 myThread2 = new MyThread2();

//5. 调用Thread类的start方法:开启线程,调用Runnable子类接口中的run方法

Thread t3 = new Thread(myThread2);

t3.start();

//再启动一个线程,输出100以内的质数

Thread t4 = new Thread(myThread2);

t4.start();

//创建匿名子类的方式创建线程

// new Thread(new MyThread2()).start();

}

}

//1. 创建一个继承于Thread类的子类

class MyThread1 extends Thread{

//2. 重写Thread类中的run()方法

@Override

public void run() {

for (int i = 0; i < 100; i++) {

if(i % 2 == 0){

System.out.println(Thread.currentThread().getName() + ":" + i);

}

}

}

}

//1. 定义子类,实现Runnable接口

class MyThread2 implements Runnable{

//2. 子类中重写Runnable接口中的run方法

@Override

public void run() {

//输出100以内的质数

label:for (int i = 2; i < 100; i++) {

for (int j = 2; j <= Math.sqrt(i); j++) {

if(i % j == 0){

continue label;

}

}

System.out.println(Thread.currentThread().getName() + ":" + i);

}

}

}

Thread中常用的方法

package com.th1024.multiplethreads.ThreadDemo;

/**

* 测试Thread中的常用方法:

* 1. start():启动当前线程,调用当前线程的run()

* 2. run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中

* 3. currentThread():静态方法,返回当前代码的线程

* 4. getName():获取当前线程的名字

* 5. setName():设置当前线程的名字

* 6. yield():释放当前cpu的执行权

* 7. join():在线程a中调用线程b的join(),此时线程a进入阻塞状态,直到线程b完全执行完之后,

* 线程a才会结束阻塞状态

* 8. sleep(long millis):让当前线程“睡眠”指定的毫秒。在这段时间内,线程是阻塞状态

* 9. isAlive():判断当前线程是否存活

*

* @author TuHong

* @create 2021-01-24 10:50

*/

public class ThreadMethodTest {

public static void main(String[] args) {

Thread1 t1 = new Thread1("Thread1");

// t1.setName("线程1");

t1.start();

//给主线程命名

Thread.currentThread().setName("主线程");

for (int i = 0; i < 100; i++) {

if(i % 2 == 0){

System.out.println(Thread.currentThread().getName() + ":" + i);

}

if(i == 20){

try {

t1.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

//判断分线程是否存活

System.out.println(t1.isAlive());

}

}

class Thread1 extends Thread{

@Override

public void run() {

for (int i = 0; i < 100; i++) {

try {

sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

if(i % 2 != 0){

System.out.println(Thread.currentThread().getName() + ":" + i);

}

// if(i % 20 == 0){

// yield();

// }

}

}

public Thread1(String name){

super(name);

}

}

两种方式解决线程不安全问题

package com.th1024.demo;

/**

* 例子:创建三个窗口卖票,总票数为100张

*

* 方式一:使用继承Thread类的方式

* 存在线程安全问题

*

* 方式二:使用实现Runnable接口的方式

* 存在线程安全问题

*

* 1. 问题:重票和错票

* 2. 原因:某个线程进行操作共享数据时,还没执行完,其它线程就参与进来也进行了操作

* 3. 解决:当一个线程操作共享数据时,其它线程不能参与进来,直到线程操作完成时,其它线程才可以操作,

* 即使该线程出现阻塞,其它线程也不能参与

* 4. 方式:同步机制

* 优点:解决了线程不安全问题

* 缺点:操作同步代码时,只能有一个线程参与,相当于单线程,效率低

*

* 方式一:同步代码块

* synchronized(同步监视器){

* //需要被同步的代码

* }

* 说明:1. 操作共享数据的代码,即为需要被同步的代码

* 2. 共享数据:多个线程共同操作的变量

* 3. 同步监视器。俗称:锁。任何一个类的对象都可以充当锁

* 要求:多个线程必须拥有同一个监视器对象

*

* 方式二:同步方法

* 如果操作共享数据的代码完整地声明在一个方法中,不妨将这个方法声明为同步方法

* 说明:1. 同步方法仍然涉及到同步监视器,只是不需要显式声明

* 2. 非静态的同步方法,同步监视器是:this

* 静态的同步方法,同步监视器是:当前类本身

*

* @author TuHong

* @create 2021-01-24 13:18

*/

class Window1 extends Thread{

private static int ticket = 100;

static Object obj = new Object();//声明为静态,每个对象共享一个静态变量

@Override

public void run() {

while(ticket > 0){

//while(true) {

//同步代码块解决继承Thread类方式的线程安全问题

// synchronized(Window1.class){//使用Window1类作为对象,只会加载一次 //synchronized (obj) {//不能使用this,Window1的对象不唯一

// if (ticket > 0) {

//

// try {

// Thread.sleep(100);

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

//

// System.out.println(getName() + ": 卖票,票号为:" + ticket);

// ticket--;

// } else {

// break;

// }

sell();

// }

}

}

private static synchronized void sell(){//同步监视器:Window1.class

//private synchronized void sell(){//同步监视器:w1,w2,w3

if (ticket > 0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + ": 卖票,票号为:" + ticket);

ticket--;

}

}

}

class Window2 implements Runnable{

private int ticket = 100;

// Object obj = new Object();

// Dog dog = new Dog();

@Override

public void run() {

while(ticket > 0){

//while(true) {

//同步代码块解决实现Runnable接口方式的线程安全问题

// synchronized(this){//this代表唯一的Window2的对象 //synchronized (dog) {

// if (ticket > 0) {

//

// try {

// Thread.sleep(100);

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

// System.out.println(Thread.currentThread().getName() + ": 卖票,票号为:" + ticket);

// ticket--;

// } else {

// break;

// }

sell();

// }

}

}

private synchronized void sell(){//同步监视器:this

if (ticket > 0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + ": 卖票,票号为:" + ticket);

ticket--;

}

}

}

public class WindowTest {

public static void main(String[] args) {

// Window1 w1 = new Window1();

// Window1 w2 = new Window1();

// Window1 w3 = new Window1();

//

// w1.setName("窗口一");

// w2.setName("窗口二");

// w3.setName("窗口三");

//

// w1.start();

// w2.start();

// w3.start();

Window2 window2 = new Window2();

Thread t1 = new Thread(window2);

Thread t2 = new Thread(window2);

Thread t3 = new Thread(window2);

t1.setName("窗口一");

t2.setName("窗口二");

t3.setName("窗口三");

t1.start();

t2.start();

t3.start();

}

}

//class Dog{

//

//}

例子:解决单例模式中的懒汉式的线程不安全问题

package com.th1024.demo;

/**

* 使用同步机制将单例模式中的懒汉式改写为线程安全的

*

* @author TuHong

* @create 2021-01-25 11:20

*/

public class BankTest {

}

class Bank{

private Bank(){}

private static Bank instance = null;

public static Bank getInstance() {

// public static synchronized Bank getInstance(){

//方式一:效率稍差

// synchronized (Bank.class) {

// if(instance == null){

// instance = new Bank();

// }

// return instance;

// }

//方式二:效率更高

if (instance == null) {

synchronized (Bank.class) {

if (instance == null) {

instance = new Bank();

}

}

}

return instance;

}

}

死锁

package com.th1024.demo;

/**

* 演示线程的死锁问题

*

* 1. 死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

*

* 2. 说明:出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续

*

*

* @author TuHong

* @create 2021-01-25 11:37

*/

public class DeadLockTest {

public static void main(String[] args) {

StringBuffer s1 = new StringBuffer();

StringBuffer s2 = new StringBuffer();

new Thread(){

@Override

public void run() {

synchronized (s1){

s1.append("a");

s2.append("1");

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(s2){

s1.append("b");

s2.append("2");

System.out.println(s1);

System.out.println(s2);

}

}

}

}.start();

new Thread(new Runnable() {

@Override

public void run() {

synchronized (s2){

s1.append("c");

s2.append("3");

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(s1){

s1.append("d");

s2.append("4");

System.out.println(s1);

System.out.println(s2);

}

}

}

}).start();

}

}

解决线程不安全问题方式三:Lock锁

package com.th1024.demo;

import java.util.concurrent.locks.ReentrantLock;

/**

* 解决线程安全问题的方式三:Lock锁 -- JDK5.0新增

*

* 1. 面试题:synchronized和lock的异同?

* 相同:都可以解决线程不安全的问题

* 不同:synchronized机制在执行完相应的同步代码以后,自动地释放同步监视器

* lock需要手动地启动同步(lock()),同时结束同步也需要手动地实现(unlock())

* 优先使用顺序:lock->同步代码块(已经进入了方法体,分配了相应资源)->同步方法(在方法体之外)

*

* 2. 面试题:如何解决线程安全问题?有几种方式?

*

* @author TuHong

* @create 2021-01-25 13:23

*/

public class LockTest {

public static void main(String[] args) {

Window w = new Window();

Thread t1 = new Thread(w);

Thread t2 = new Thread(w);

Thread t3 = new Thread(w);

t1.setName("窗口一");

t2.setName("窗口二");

t3.setName("窗口三");

t1.start();

t2.start();

t3.start();

}

}

class Window implements Runnable {

private int ticket = 100;

//1.实例化ReentrantLock

private ReentrantLock lock = new ReentrantLock();

@Override

public void run() {

while (true) {

try{

//2. 调用锁定方法:lock()

lock.lock();

if (ticket > 0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + ":售出,票号为 - " + ticket);

ticket--;

} else {

break;

}

}finally {

//3. 调用解锁方法:unlock()

lock.unlock();

}

}

}

}

创建多线程的另外两种方式

实现Callable接口

package com.th1024.demo;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.FutureTask;

/**

* 创建线程的方式三:实现Callable接口。-- JDK5.0新增

*

* 如何理解实现Callable接口的方式创建多线程比实现Runnable接口的方式强大?

* 1. call()方法可以有返回值

* 2. call()可以抛出异常

* 3. Callable支持泛型

*

* @author TuHong

* @create 2021-01-25 16:06

*/

//1. 创建一个实现Callable接口的实现类

class NumThread implements Callable{

//2. 实现call(),将此线程需要执行的操作声明在call()中

@Override

public Object call() throws Exception {

int sum = 0;

for (int i = 0; i <= 100; i++) {

if(i % 2 == 0){

System.out.println(i);

sum += i;

}

}

return sum;

}

}

public class ThreadNew {

public static void main(String[] args) {

//3. 创建Callable接口实现类的对象

NumThread numThread = new NumThread();

//4. 将此Callable接口实现类的对象作为参数传递到FutureTask构造器中

FutureTask futureTask = new FutureTask(numThread);

//5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象并start()

new Thread(futureTask).start();

try {

//6. 获取Callable中call()的返回值

//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值

Object sum = futureTask.get();

System.out.println("总和为:" + sum);

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

}

使用线程池

package com.th1024.demo;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.ThreadPoolExecutor;

/**

* 创建线程的方式四:使用线程池

*

* 好处:

* 提高响应速度(减少了创建新线程的时间)

* 降低资源消耗(重复利用线程池中,不需要每次都创建)

* 便于线程管理

* corePoolSize:核心池的大小

* maximumPoolSize:最大线程数

* keepAliveTime:线程没有任务时最多保持多长时间后会终止

*

* @author TuHong

* @create 2021-01-25 16:30

*/

class NumberThread implements Runnable{

@Override

public void run() {

for (int i = 0; i <= 100; i++) {

if(i % 2 == 0){

System.out.println(Thread.currentThread().getName() + ":" + i);

}

}

}

}

class NumberThread1 implements Runnable{

@Override

public void run() {

for (int i = 0; i <= 100; i++) {

if(i % 2 != 0){

System.out.println(Thread.currentThread().getName() + ":" + i);

}

}

}

}

public class ThreadPool {

public static void main(String[] args) {

//1. 提供指定线程数量的线程池

ExecutorService service = Executors.newFixedThreadPool(10);

ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;

//设置线程池的属性

// System.out.println(service.getClass());

// service1.setCorePoolSize(15);

// service1.setKeepAliveTime(10);

//2. 执行指定的线程操作,需提供实现Runnable接口或Callable接口实现类的对象

service.execute(new NumberThread());//适用于Runnable

service.execute(new NumberThread1());//适用于Runnable

// service.submit();//适用于Callable

//3. 关闭连接池

service.shutdown();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值