JAVA之多线程
程序员文章站
2023-12-23 13:24:52
...
JAVA之多线程
- 并发与并行
并发(concurrency)和并行(parallellism)是:
解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
解释三:并行是在一台处理器上“同时”处理多个任务,并发是在多台处理器上同时处理多个任务。如 hadoop 分布式集群。
并行:是逻辑上同时发生,指在某一个时间内同时运行多个程序。
并发:是物理上同时发生,指在某一个时间点同时运行多个程序。
- 获取和设置线程对象名称
* Thread类的基本获取和设置方法
public final String getName()//获取线程名称
public final void setName(String name)//设置线程名称
public static Thread currentThread()//获取当前执行的线程
- 线程优先级的获取和设置线程优先级
如何设置和获取线程优先级
public final int getPriority() //获取线程的优先级
public final void setPriority(int newPriority)//设置线程的优先级
注意事项: 有的时候我们给线程设置了指定的优先级,但是该线程并不是按照优先级高的线程执行,那是为什么呢?
因为线程的优先级的大小仅仅表示这个线程被CPU执行的概率增大了.但是我们都知道多线程具有随机性,
* 获取线程的优先级:
public final int getPriority()返回线程的优先级。
* 线程的默认优先级是5
* 给线程设置优先级:
public final void setPriority(int newPriority)
- 线程控制之休眠线程
* 线程休眠: public static void sleep(long millis) 线程休眠
//线程会休眠相应时间的时间然后再去执行
- 线程控制之加入线程
* 加入线程: public final void join()
//在该方法的调用者调用执行结束后其他的线程才能进行,在start执行之后
- 线程控制之守护线程
守护线程: public final void setDaemon(boolean on):
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
//在start执行之前
//设置守护线程后,主线程结束,守护线程也会结束
Java守护线程和Linux守护进程
两者不是一个概念。Linux守护进程是后台服务进程,没有控制台。
在Windows中,你可以运行javaw来达到释放控制台的目的,在Unix下你加&在命令的最后就行了。所以守护进程并非一定需要的。
- 多线程程序实现的方式2
* 实现Runnable接口 这种方式扩展性强 实现一个接口 还可以再去继承其他类
a:如何获取线程名称
b:如何给线程设置名称
c:实现接口方式的好处
可以避免由于Java单继承带来的局限性。
- 多线程程序实现的方式3
* 实现 Callable 接口。 相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
* :执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。 FutureTask 是 Future 接口的实现类
* 实现步骤
1.创建一个类实现Callable 接口
2.创建一个FutureTask类将Callable接口的子类对象作为参数传进去
3.创建Thread类,将FutureTask对象作为参数传进去
4.开启线程
- 线程安全问题的产生原因分析
是否是多线程环境
是否有共享数据
是否有多条语句操作共享数据
- 同步代码块的方式解决线程安全问题及解释以及同步的特点及好处和弊端
* 同步代码块的格式
格式:
synchronized(对象){
需要同步的代码;
}
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能
同步的好处: 同步的出现解决了多线程的安全问题。
同步的弊端: 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
public class CellRunnable implements Runnable{
//共享数据,被多个线程所共享。
static int piao = 100;
static Object obj=new Object();
int i=0;
@Override
public void run() {
while (true) {
if(i%2==0){
//就是最后一张。piao=1;
synchronized (CellRunnable.class) {
//加锁
try {
//模拟真实情况中,网络延迟的现象。
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (piao > 0) {
System.out.println(Thread.currentThread().getName() + " 正在出售:" + (piao--) + " 张票");
}
}
//释放锁
}else{
maiPiao2();
//释放锁
}
i++;
}
}
//方法上加上关键字synchronized 同步方法
//同步方法的默认锁对象是this
public synchronized void maiPiao(){
//就是最后一张。piao=1;
//加锁
try {
//模拟真实情况中,网络延迟的现象。
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (piao > 0) {
System.out.println(Thread.currentThread().getName() + " 正在出售:" + (piao--) + " 张票");
}
}
//静态同步方法,用的锁对象是当前类的字节码文件对象
public static synchronized void maiPiao2() {
//就是最后一张。piao=1;
//加锁
try {
//模拟真实情况中,网络延迟的现象。
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (piao > 0) {
System.out.println(Thread.currentThread().getName() + " 正在出售:" + (piao--) + " 张票");
}
}
}
- 需求:卖电影票案例
public class test1 {
public static void main(String[] args) {
//卖票
selltickets s = new selltickets();
Thread t1 = new Thread(s, "窗口1");
Thread t2 = new Thread(s, "窗口2");
Thread t3 = new Thread(s, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
class selltickets implements Runnable {
private static int num = 100;
Object o = new Object();
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o) {//每次只能有一个线程去操作
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + num + "张票");
num--;
}
}
}
}
}
- 需求:多个线程复制一个文件
public class test21 {
public static void main(String[] args) throws FileNotFoundException {
File file = new File("C:\\Users\\优小熊Xx\\Desktop\\m1.mp3");
File newfile = new File("C:\\Users\\优小熊Xx\\Desktop\\mm1.mp3");
long length = file.length();
long num = 3;
long copylength = length / num;
for (int i = 0; i < num; i++) {
long start = i * copylength;
long end = (i + 1) * copylength;
new ThreadCopy(start, end, file, newfile).start();
}
}
}
class ThreadCopy extends Thread {
long start;
long end;
RandomAccessFile in = null;
RandomAccessFile out = null;
public ThreadCopy(long start, long end, File file, File newfile) throws FileNotFoundException {
this.start = start;
this.end = end;
in = new RandomAccessFile(file, "rw");
out = new RandomAccessFile(newfile, "rw");
}
@Override
public void run() {
try {
in.seek(start);
out.seek(start);
int len = 0;
byte[] bytes = new byte[1024 * 1024];
if (start < end) {
while ((len = in.read(bytes)) != -1) {
start = start + len;
out.write(bytes, 0, len);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}