Python 官方文档:入门教程 => 点击学习
什么是线程 线程被称为轻量级进程,是程序执行的最小单位,它是指在程序执行过程中,能够执行代码的一个执行单位。每个程序程序都至少有一个线程,也即是程序本身。 线程
继承Thread
class MyThread extends Thread{
@Override
public void run() {
System.out.println(currentThread().getName()+"运行了");
}
}
class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
System.out.println(Thread.currentThread().getName()+":运行了");
myThread.start();
}
}
实现Runable接口创建多线程
class MThread implements Runnable{
@Override
public void run() {
for (int i = 0; i<100;i++){
if (i%2!=0){
System.out.println(i);
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
//3.创建实现类的对象
MThread mThread = new MThread();
//4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread thread = new Thread(mThread);
thread.start();
}
}
Thread和Runable创建多线程对比
开发中:优先使用Runable
1.实现的方式没有类的单继承的局限性。
2.实现的方式跟适合处理多个线程有共享数据的情况。
联系:Thread类中也实现了Runable,两种方式都需要重写run()。
实现Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum=0;
for(int i=0;i<100;i++){
sum+=i;
}
return sum;
}
}
public class CallableTest {
public static void main(String[] args) {
//执行Callable 方式,需要FutureTask 实现实现,用于接收运算结果
FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new MCallable());
new Thread(integerFutureTask).start();
//接受线程运算后的结果
Integer integer = null;
try {
integer = integerFutureTask.get();
System.out.println(integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
与Runable相比,Callable功能更强大
相比run()方法可以有返回值
方法可以抛出异常
支持泛型的返回值
需要借助FutureTask类,比如获取返回结果
线程池创建的好处
提高响应速度(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
便于线程管理:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Thread1 implements Runnable{
@Override
public void run() {
for (int i=1;i<30;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class ThreadPool {
public static void main(String[] args) {
//创建线程池
ExecutorService executorService= Executors.newFixedThreadPool(10);
Thread1 threadPool = new Thread1();
for (int i=0;i<5;i++){
//为线程池分配任务
executorService.submit(threadPool);
}
//关闭线程池
executorService.shutdown();
}
}
Thread中的常用方法
线程的优先级等级
涉及的方法
说明
多线程卖票
基于实现Runable的方式实现多线程买票
package demo2;
class Thread2 implements Runnable{
private int ticket=100;
@Override
public void run() {
while (true){
if (ticket>0) {
System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
ticket--;
}else {
break;
}
}
}
}
public class Test1 {
public static void main(String[] args) {
Thread2 thread2 = new Thread2();
Thread t1 = new Thread(thread2);
Thread t2 = new Thread(thread2);
Thread t3 = new Thread(thread2);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
实现结果,存在重复的票
如果在买票方法中加入sleep函数
public void run() {
while (true){
if (ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
ticket--;
}else {
break;
}
}
}
则运行结果可能会出现-1,表示也是不正常的
理想情况
极端情况
在java中,我们通过同步机制,来解决线程的安全问题。
synchronized(同步监视器){
//需要被同步的代码
}
说明
修改之后的代码:
package demo2;
class Thread2 implements Runnable{
private int ticket=100;
Object object = new Object();
@Override
public void run() {
while (true){
synchronized(object) { //括号中的内容可以直接使用当前对象this去充当
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
public class Test1 {
public static void main(String[] args) {
Thread2 thread2 = new Thread2();
Thread t1 = new Thread(thread2);
Thread t2 = new Thread(thread2);
Thread t3 = new Thread(thread2);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
结果
继承Thread的方式,去使用同步代码块,需要将声明的锁对象设为statci,否则创建的对象的同步监视器不唯一,就无法实现。
package demo2;
class WindowsTest2 extends Thread{
private static int ticket=100;
private static Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){ //这里不能使用this去充当,可以直接写一个Test.class 类也是对象
if (ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+":买票,票号为:"+ticket);
ticket--;
}else {
break;
}
}
}
}
}
public class Test2{
public static void main(String[] args) {
WindowsTest2 w1 = new WindowsTest2();
WindowsTest2 w2 = new WindowsTest2();
WindowsTest2 w3 = new WindowsTest2();
w1.setName("窗口一");
w2.setName("窗口二");
w3.setName("窗口三");
w1.start();
w2.start();
w3.start();
}
}
如果操作共享数据的代码完整的声明在一个方法中,可以将此方法声明为同步的。
通过实现Runable的方式实现同步方法。
package demo2;
class Thread3 implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
show();
}
}
private synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
ticket--;
}
}
}
public class Test3 {
public static void main(String[] args) {
Thread3 thread3 = new Thread3();
Thread t1 = new Thread(thread3);
Thread t2 = new Thread(thread3);
Thread t3 = new Thread(thread3);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
通过实现继承Thread的方式实现同步方法。使用的同步监视器是this,则不唯一,就会报错。所以将该方法定义为static。当前的同步换时期就变成Test4.class了
package demo2;
class WindowsTest4 extends Thread{
private static int ticket=100;
private static Object obj = new Object();
@Override
public void run() {
while (true){
show();
}
}
public static synchronized void show(){//同步监视器不是this了,而是当前的类
// public synchronized void show(){//同步监视器是this ,t1,t2,t3
if (ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":买票,票号为:"+ticket);
ticket--;
}
}
}
public class Test4{
public static void main(String[] args) {
WindowsTest4 w1 = new WindowsTest4();
WindowsTest4 w2 = new WindowsTest4();
WindowsTest4 w3 = new WindowsTest4();
w1.setName("窗口一");
w2.setName("窗口二");
w3.setName("窗口三");
w1.start();
w2.start();
w3.start();
}
}
synchronize与lock的异同
相同
不同
建议优先使用顺序
Lock------>同步代码块(已经进入了方法体,分配了相应资源)---->同步方法(在方法体之外)
package demo2;
import java.util.concurrent.locks.ReentrantLock;
class Lock1 implements Runnable{
private int ticket=50;
//1.实例化
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.调用解锁方法
lock.unlock();
}
}
}
}
public class LockTest1 {
public static void main(String[] args) {
Lock1 lock1 = new Lock1();
Thread t1 = new Thread(lock1);
Thread t2 = new Thread(lock1);
Thread t3 = new Thread(lock1);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
到此这篇关于java多线程创建及线程安全的文章就介绍到这了,更多相关java多线程创建内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: java多线程创建及线程安全详解
本文链接: https://www.lsjlt.com/news/125781.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0