JAVA API 学习笔记——多线程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言:

什么是多线程?

多线程是指一个应用程序同时执行多个任务,一般来说一个任务就是一个线程 ,而一个应用程序有一个以上的线程我们称之为多线程。

一、进程和线程的区别

线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。

二、在Java中实现线程?

在语言层面有两种方式。java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口,所以你可以继承java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。

用Runnable还是Thread?

1.Thread:

新建一个Thread类:

package com.google.demo;

public class BBThread extends Thread{
    @Override
    public void run() {

        while(true) {
            System.out.println("hey you get it");
        }
    }
}

测试使用多线程:

package com.google.demo;

public class Demo {
    public static void main (String[] args){


        BBThread bbThread = new BBThread();
        bbThread.start();
        while(true) {
            System.out.println("1111111111111111");
        }
    }
}


结果:
1111111111111111
1111111111111111
hey you get it
1111111111111111
hey you get it
......(省略无限循环的输出)

2.Runnable:

新建类实现Runnable接口抢鞋:

package com.google.demo;

public class BBRunnable implements Runnable{
    private int shoe = 10;
    @Override
    public void run() {

        while(true){
            if(shoe>0){
                System.out.println(Thread.currentThread().getName()+"抢到了第"+(shoe--)+"双鞋");
            }
        }

    }
}

测试使用多线程抢鞋:

package com.google.demo;

public class Demo {
    public static void main (String[] args){
        BBRunnable bbRunnable = new BBRunnable();
        new Thread(bbRunnable,"doinb").start();
        new Thread(bbRunnable,"crisp").start();
        new Thread(bbRunnable,"gimgong").start();


    }
}

输出:
gimgong抢到了第8双鞋
crisp抢到了第9双鞋
doinb抢到了第10双鞋
crisp抢到了第6双鞋
gimgong抢到了第7双鞋
crisp抢到了第4双鞋
doinb抢到了第5双鞋
crisp抢到了第2双鞋
gimgong抢到了第3双鞋
doinb抢到了第1双鞋

3. Daemon:

程序定义了一个守护线程,并且该守护线程将一直进行信息输出,但是通过执行的结果可以发现,当用户线程消失后守护线程也同时结束。

定义一个Daemon类:

package com.google.demo;

public class DaemonTest implements Runnable{
    @Override
    public void run() {
        System.out.println("保护保护保护保护保护保护");
    }
}

测试守护线程:

package com.google.demo;

public class Demo {
    public static void main (String[] args){
    DaemonTest daemonTest = new DaemonTest();
    BBRunnable bbRunnable = new BBRunnable();

    Thread daeThread = new Thread(daemonTest);
    daeThread.start();

    new Thread(bbRunnable,"doinb").start();
    new Thread(bbRunnable,"doinb").start();



    }
}


三、问题的引入:

1.使用runnable抢鞋发生的问题:

抢鞋线程:

package com.google.demo;

public class BBRunnable implements Runnable{
    private int shoe = 10;
    @Override
    public void run() {

        while(true){
            if(shoe>0){
                try {
                    Thread.sleep(1000);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+
                        "抢到了第"+ (shoe--)+"双鞋");
            }
        }

    }
}

测试线程:

public class Demo {
    public static void main (String[] args){
    BBRunnable bbRunnable = new BBRunnable();

    new Thread(bbRunnable,"doinb").start();
    new Thread(bbRunnable,"lwx").start();


    }
}

结果:
doinb抢到了第9双鞋
lwx抢到了第10双鞋
lwx抢到了第8双鞋
doinb抢到了第8双鞋
lwx抢到了第7双鞋
doinb抢到了第6双鞋
lwx抢到了第5双鞋
doinb抢到了第5双鞋
lwx抢到了第4双鞋
doinb抢到了第4双鞋
doinb抢到了第3双鞋
lwx抢到了第3双鞋
lwx抢到了第2双鞋
doinb抢到了第2双鞋
lwx抢到了第1双鞋
doinb抢到了第1双鞋

运行速度快时,导致线程不同步。

2.Synchronized的提出:

synchronized是Java中的关键字,是一种同步锁。
一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞。

package com.google.demo;

public class BBRunnable implements Runnable{
    private int shoe = 10;

    Object lock = new Object();
    @Override
    public void run() {

        while (true) {
//      同步代码块
            synchronized (lock) {
            if (shoe > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() +
                        "抢到了第" + (shoe--) + "双鞋");
            }
        }
    }
    }
}

3.Synchronized的优化:

ReentrantLock(同步锁)方法:

package com.google.demo;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BBRunnable implements Runnable{
    private int shoe = 10;

    //    同步锁
    Lock reentrantLock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            reentrantLock.lock();
            if (shoe > 0) {
                try {
                //     线程休眠
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() +
                        "抢到了第" + (shoe--) + "双鞋");
            }
            reentrantLock.unlock();
        }
    }
}

四、线程的调度:

每一个线程的有限使用权都是系统随机分配人人平等的,谁先分配到谁先用。

更改调度优先级(无法达到完全优先):

package com.google.demo;

public class Demo {
    public static void main (String[] args){
    Thread minThread = new Thread((Runnable) new MinThread(),"minThread");
    Thread maxThread = new Thread((Runnable) new MaxThread(),"maxThread");

    maxThread.setPriority(Thread.MIN_PRIORITY);
    minThread.setPriority(Thread.MAX_PRIORITY);

    minThread.start();
    maxThread.start();
    }
}


线程插队:Thread.join()

package com.google.demo;

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

        Thread bbThread = new Thread(new BBThread(),"bbThread");
        bbThread.start();

    //  线程插队
    for (int i = 1; i <8 ; i++) {
            System.out.println(Thread.currentThread().getName());
            if(i == 5){
                bbThread.join();
            }
        }

    }
}

输出:
main
main
main
main
main
bbThread
bbThread
bbThread
bbThread
main
main

线程调度:Thread.yield()

package com.google.demo;

public class BBThread extends Thread{
    @Override
    public void run() {
        for(int i = 1;i<8;i++){
            if(i==5) {
                System.out.println(Thread.currentThread().getName()+"========线程开始让步");
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName());
        }

    }
}
// 输出到5次开始让步,程序太快导致先让步后显示
输出:
11111111
11111111
11111111
11111111
22222222
22222222
22222222
22222222
11111111========线程开始让步
22222222========线程开始让步
22222222
22222222
22222222
11111111
11111111
11111111

五、线程状态:

在这里插入图片描述
斗地主——新建;
开始游戏——可运行;
抢地主——抢锁;
地主先出牌——阻塞;
等待——另外两位玩家等待出牌;
计时等待——20秒出牌时间;
终止——游戏结束;

线程的通信:notify

新建Condom对象:

package com.google.demo;

public class Condom {
    public boolean isStatus = false;
}

新建用户线程类:

package com.google.demo;

public class Customer extends Thread{
    private Condom condom = new Condom();
    public Customer(Condom condom){
    this.condom = condom;
    }
    @Override
    public void run(){
        while(true){
            synchronized (condom){
                if(condom.isStatus ==false) {
                    try {
                        condom.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                condom.isStatus = false;
                System.out.println(Thread.currentThread().getName()+"买完了铁子们");
                condom.notify();

            }
        }
    }
}




新建生产者线程类:

package com.google.demo;

public class Producer extends Thread {
    private Condom condom = new Condom();
    public Producer(Condom condom){
        this.condom = condom;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (condom) {
                if (condom.isStatus == true) {
                    try {
                        condom.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                    condom.isStatus = true;
                    System.out.println(Thread.currentThread().getName() + "生产出来了铁子们");
                    condom.notify();

            }
        }
    }
}


测试效果:

package com.google.demo;

public class Demo {
    public static void main (String[] args) throws InterruptedException {
    Condom condom = new Condom();

    Producer producer = new Producer(condom);
    Customer customer = new Customer(condom);
    producer.start();
    customer.start();
    }
}
输出:
Thread-0生产出来了铁子们
Thread-1买完了铁子们
Thread-0生产出来了铁子们
Thread-1买完了铁子们
Thread-0生产出来了铁子们

notify():

notify() 方法随机唤醒对象的等待池中的一个线程,进入锁池;
notifyAll() 唤醒对象的等待池中的所有线程,进入锁池。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
文件上传是Web开发中常见的功能之一,Java中也提供了多种方式来实现文件上传。其中,一种常用的方式是通过Apache的commons-fileupload组件来实现文件上传。 以下是实现文件上传的步骤: 1.在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> ``` 2.在前端页面中添加文件上传表单: ```html <form method="post" enctype="multipart/form-data" action="upload"> <input type="file" name="file"> <input type="submit" value="Upload"> </form> ``` 3.在后台Java代码中处理上传文件: ```java // 创建一个DiskFileItemFactory对象,用于解析上传的文件 DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置缓冲区大小,如果上传的文件大于缓冲区大小,则先将文件保存到临时文件中,再进行处理 factory.setSizeThreshold(1024 * 1024); // 创建一个ServletFileUpload对象,用于解析上传的文件 ServletFileUpload upload = new ServletFileUpload(factory); // 设置上传文件的大小限制,这里设置为10MB upload.setFileSizeMax(10 * 1024 * 1024); // 解析上传的文件,得到一个FileItem的List集合 List<FileItem> items = upload.parseRequest(request); // 遍历FileItem的List集合,处理上传的文件 for (FileItem item : items) { // 判断当前FileItem是否为上传的文件 if (!item.isFormField()) { // 获取上传文件的文件名 String fileName = item.getName(); // 创建一个File对象,用于保存上传的文件 File file = new File("D:/uploads/" + fileName); // 将上传的文件保存到指定的目录中 item.write(file); } } ``` 以上代码中,首先创建了一个DiskFileItemFactory对象,用于解析上传的文件。然后设置了缓冲区大小和上传文件的大小限制。接着创建一个ServletFileUpload对象,用于解析上传的文件。最后遍历FileItem的List集合,判断当前FileItem是否为上传的文件,如果是,则获取文件名,创建一个File对象,将上传的文件保存到指定的目录中。 4.文件上传完成后,可以给用户一个提示信息,例如: ```java response.getWriter().write("File uploaded successfully!"); ``` 以上就是使用Apache的commons-fileupload组件实现文件上传的步骤。需要注意的是,文件上传可能会带来安全隐患,因此在处理上传的文件时,需要进行严格的校验和过滤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值