java—线程的使用

** 概念

进程:简单说就是一个正在运行的程序。进程负责分配程序的内存空间等资源。

线程:一个进程的某个执行流程。一个进度可以有多个线程。进程中的多个线程共享进程的内存。

多线程就是一个进程中有多个线程同时进行。

对于电脑,多个程序同时运行,其实是CPU的分时机制在起作用,不过现在都是多核的电脑了。

多线程意味这可以在一个进程里同时执行多个任务。而且可以提高资源的利用率。

# 如何使线程

方式一、继承自Thread类

>>
继承自Thread类

>>
重写run()方法

>>
创建继承自Thread类的实例

>>
调用start()方法开启线程


publicclass Tm05
extends Thread{

/**

* 一个程序就是一个进程,进程负责分配内存

* 一个进程有多个线程[多线程]可以执行不同的任务,线程负责CPU资源的抢夺

* 多线程提高了资源的利用率

* 对于单核的电脑对于微观来说是单进程的

* 任何一个java程序,jvm在运行的时候创建一个主线程,来执行main中的代码

* 任何一个java程序,至少有两个线程[1.main | 2.垃圾回收器[GC]]

*/

@Override

public
void
run() {

//
自定义线程的任务代码定义在run()方法中

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

System.out.println("run()+"+(i+1));

}

}

public
static void
main(String[]
args){

System.out.println("多线程使用");

System.out.println("#继承Thread类 
| #重写run()方法 
| #创建Thread实例,并调用start()方法");

System.out.println("注意不要调用run()方法");

Tm05 t=new Tm05();

t.start();;

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

System.out.println("main()+"+(i+1));

}

}

}

方式二、实现Runnable接口[tips:推荐使用第二种,因为java是单继承多实现的]

>>实现Runnable接口

>>重写run()方法

>>创建Runnable接口子类的实例

>>创建Thread类实例,并将Runnable接口子类的实例作为实参传入到构造方法

>>由Thread类的实例调用start()方法开启线程[start()方法在Thread类中]


package hs;

/**

*
推荐使用第二种[这种]

*
因为java是单继承多实现的,如果用了继承Thread类,其他类就不能继承了

*/

publicclass Tm10
implements Runnable{

static Object
lockState=new Object();

//
方式二中Tm10只是共享了一份代码而已,所以不用加static

int
num=100;

@Override

public
void
run() {

while(true){

synchronized (lockState) {

if(num>0){

num--;

System.out.println(Thread.currentThread().getName()+"卖出1张,还有"+num+"张");

}else{

System.out.println("已经买完了......");

break;

}

}

}

}

public
static void
main(String[]
args) {

Tm10 t=new Tm10();

Thread t1=new Thread(t,
"A");

Thread t2=new Thread(t,
"B");

Thread t3=new Thread(t,
"C");

t1.start();

t2.start();

t3.start();

}

}

** 线程的状态和常见的方法

就绪状态:状态的线程位于可运行线程池中,等待获取cpu的执行权

临时阻塞状态:线程因为某种原因放弃CPU使用权,暂时停止运行

运行状态:就绪状态的线程获取了CPU执行权,执行程序代码

常见的线程方法


publicclass Tm12
implements Runnable{

@Override

public
void
run() {

int
i=0;

while(true){

i++;

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

if(i>=10){

break;

}

}

}

/**

* 常用的线程方法

* @throws InterruptedException

*/

public
static void
main(String[]
args) throws InterruptedException {

Tm12 t=new Tm12();

Thread th=new Thread(t,
"my thread");

// # setName()
设置线程的名字

th.setName("set thread name");

// # setPriority()
设置当前线程的优先级

th.setPriority(10);

// # start()
开启线程

th.start();

// # sleep()
让线程睡眠XXX毫秒对于sleep是对当前运行的线程有效果

Thread.sleep(1000);

// # setDaemon()
设置是否为守护线程

th.setDaemon(true);

// #
还有notify()/notifyAll()、wait()等方法后面讲

// # currentThread()
获取当前线程对象

Thread thMain=Thread.currentThread();

for(int
i=1;i<=10;i++){

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

}

}

}

** 同步代码块和同步函数

同步代码块[同步代码块比较容易控制锁对象,所以推荐使用同步代码块]


@Override

public
void
run() {

while (true) {

synchronized (lockState) {

if (num > 0) {

num--;

System.out.println(Thread.currentThread().getName()+"成功卖出1张票,还有:"
+ this.num +
"张");

} else {

System.out.println("已经买完了票......");

break;

}

}

}

}

同步函数


// 静态同步函数 -->
锁对象是唯一的

// **推荐使用同步代码块**

public
static synchronizedvoid
getMoney(){

while(true){

if(money-1000>0){

money=money-1000;

System.out.println(Thread.currentThread().getName()+"取了1000,还有"+money);

}else{

System.out.println("对不起余额不足......");

break;

}

}

}

** 锁对象

Java中的每个对象都有一个内置锁,只有当对象具有同步方法代码时,内置锁才会起作用,当进入一个同步的非静态方法时,就会自动获得与类的当前实例(this)相关的锁,该类的代码就是正在执行的代码。获得一个对象的锁也成为获取锁、锁定对象也可以称之为监视器来指我们正在获取的锁对象。

因为一个对象只有一个锁,所有如果一个线程获得了这个锁,其他线程就不能获得了,直到这个线程释放(或者返回)锁。也就是说在锁释放之前,任何其他线程都不能进入同步代码(不可以进入该对象的任何同步方法)。释放锁指的是持有该锁的线程退出同步方法,此时,其他线程可以进入该对象上的同步方法。

1:只能同步方法(代码块),不能同步变量或者类

2:每个对象只有一个锁

3:不必同步类中的所有方法,类可以同时具有同步方法和非同步方法

4:如果两个线程要执行一个类中的一个同步方法,并且他们使用的是了类的同一个实例(对象)来调用方法,那么一次只有一个线程能够执行该方法,另一个线程需要等待,直到第一个线程完成方法调用,总结就是:一个线程获得了对象的锁,其他线程不可以进入该对象的同步方法。

5:如果类同时具有同步方法和非同步方法,那么多个线程仍然可以访问该类的非同步方法。

同步会影响性能(甚至死锁),优先考虑同步代码块。

6:如果线程进入sleep()睡眠状态,该线程会继续持有锁,不会释放。

** 生产者和消费者

[百度百科]
生产者消费者问题(英语:Producer-consumerproblem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

wait:告诉当前线程放弃执行权,并放弃监视器(锁)并进入阻塞状态,直到其他线程持有获得执行权,并持有了相同的监视器(锁)并调用notify为止。

notify:唤醒持有同一个监视器(锁)中调用wait的第一个线程,例如,餐馆有空位置后,等候就餐最久的顾客最先入座。注意:被唤醒的线程是进入了可运行状态。等待cpu执行权。

notifyAll:唤醒持有同一监视器中调用wait的所有的线程。

如何解决生产者和消费者的问题?

可以通过设置一个标记,表示数据的(存储空间的状态)例如,当消费者读取了(消费了一次)一次数据之后可以将标记改为false,当生产者生产了一个数据,将标记改为true。

,也就是只有标记为true的时候,消费者才能取走数据,标记为false时候生产者才生产数据。


package hs;

import java.util.ArrayList;

import java.util.List;

/**

*
产品类

*/

class Product{

String name;

double
price;

public Product(String
name, doubleprice) {

this.name=name;

this.price=price;

}

}

/**

*
生产者

*/

class Producer
implements Runnable{

static
int
i=0;

List<Product>
p;

public Producer(List<Product> p) {

this.p=p;

}

@Override

public
void
run() {

while(true){

synchronized (p) {

if(p.size()<10){

Product
pro;

if(i%2==0){

pro=new Product("西瓜",2.99);

p.add(pro);

i++;

}else{

pro=new Product("桃子", 4.88);

p.add(pro);

i++;

}

System.out.println(Thread.currentThread().getName()+":生产了一个"

+pro.name+",价格是"+pro.price+"¥");

//
通知唤醒的线程

p.notify();

}else{

System.out.println(Thread.currentThread().getName()+":存储区域已经满了......");

try {

p.wait();

} catch (InterruptedException
e) {

e.printStackTrace();

}

}

}

}

}

}

/**

*
消费者

*/

class Consumer
implements Runnable{

List<Product>
p;

public Consumer(List<Product> p) {

this.p=p;

}

@Override

public
void
run() {

while(true){

synchronized (p) {

if(p.size()>0){

System.out.println(Thread.currentThread().getName()+

":取出了一个"+p.get(0).name+",价格"+p.get(0).price+"¥");

p.remove(0);

p.notify();

}else{

System.out.println(Thread.currentThread().getName()+":物品已经被取完......");

try {

p.wait();

} catch (InterruptedException
e) {

e.printStackTrace();

}

}

}

}

}

}

publicclass Tm11 {

public
static void
main(String[]
args) {

List<Product>
p=new ArrayList<Product>();

Producer producer=new Producer(p);

Consumer consumer=new Consumer(p);

Thread th1=new Thread(producer,
"生产者");

Thread th2=new Thread(consumer,"消费者");

th1.start();

th2.start();

}

}

** 其他

后台线程:就是隐藏起来一直在默默运行的线程,直到进程结束。

setDaemon(booleanon)

当所有的非后台线程结束时,程序也就终止了同时还会杀死进程中的所有后台线程,也就是说,只要有非后台线程还在运行,程序就不会终止,执行main方法的主线程就是一个非后台线程。

必须在启动线程之前(调用start方法之前)调用setDaemon(true)方法,才可以把该线程设置为后台线程。

join方法

当A线程执行到了B线程Join方法时A就会等待,等B线程都执行完A才会执行,Join可以用来临时加入线程执行

时间: 2024-10-17 20:11:21

java—线程的使用的相关文章

java 线程详解

5月7号  周末看了一下线程方面的内容 ,边看视频边看书还附带着参考了很多人的博客,一天的收获,写下来整理一下:感觉收获还是挺多的:过段时间可能看完java  这几大块要去看一下关于spring boot  的内容顺便  也整理一下:附上我参考的 几本书: 关于java  线程,首先要了解一下线程和进程之间的关系.区别以及他们之间的概念: 首先是线程: 什么是线程? 线程是在程序执行过程中能够执行部分代码的一个执行单元,也看看做是一个轻量级的进程:线程是程序内的程序控制流只能使用程序内分配给程序

Java线程工作内存与主内存变量交换过程及volatile关键字理解

Java线程工作内存与主内存变量交换过程及volatile关键字理解 1. Java内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行.此处的所谓内存模型要区别于通常所说的虚拟机堆模型: 2. 线程独有的工作内存和进程内存(主内存)之间通过8中原子操作来实现,如下图所示: 原子操作的规则(部分): 1) read,load必须连续执行,但是不保证原子性. 2) store,write必须连续执行,但是不保证原子性. 3) 不能丢失变量最后一次ass

java线程

Java线程详解 1.操作系统中的线程和进程讲解: 现在的操作系统大都是多任务操作系统,多线程是多任务的一种. 进程是指操作系统中运行的一个程序,每个进程都有自己的一块内存空间,一个进程中可以启动多个线程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. Java线程的两种具体实现方法: 第一种继承:具体代码实现如下: Public (

Java 线程第三版 第四章 Thread Notification 读书笔记

一.等待与通知 public final void wait() throws InterruptedException 等待条件的发生. public final void wait(long timeout) throws InterruptedException 等待条件的发生.如果通知没有在timeout指定的时间内发生,它还是会返回. public final void wait(long timeout, int nanos) throws InterruptedException

Java线程使用大全

1.线程实现 1.Thread类 构造方法: 案例代码: public class Ex10_1_CaseThread extends Thread {// 创建一个类继承(extend)Thread类 String studentName; public Ex10_1_CaseThread(String studentName) {// 定义类的构造函数,传递参数 System.out.println(studentName + "申请访问服务器"); this.studentNam

java线程五种状态

java线程五种状态: 创建 -> 就绪 -> 运行 -> 销毁 创建 -> 就绪 -> 运行 -> 等待(缺少资源) -> 销毁 下图:各种状态转换

java线程详细介绍

目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1

java 线程通信

java 线程通信使用wait notify 配合synchronized 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态.当执行notify/notifyAll方法时,会唤醒一个处于等待该 对象锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁. 如下代码: public class ThreadTest { //声明一个线程可视化的list集合 public static List<String> lis

分享一个java线程专栏

专栏 : java线程基础 转载自 http://blog.csdn.net/column/details/yinwenjiethread.html 专栏内容: 1.线程基础:线程(1)--操作系统和线程原理 2.线程基础:线程(2)--JAVA中的基本线程操作(上) 3. 线程基础:线程(3)--JAVA中的基本线程操作(中) 4.线程基础:线程(4)--JAVA中的基本线程操作(下) 5.线程基础:线程池(5)--基本使用(上) 6.线程基础:线程池(6)--基本使用(中) 7.线程基础:线

Java线程经典面试题

53道Java线程面试题 下面是Java线程相关的热门面试题,你可以用它来好好准备面试. 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒.Java在语言层面对多线程提供了卓越的支持,它也是一个很好的卖点. 2) 线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并