新手初学Java网络编程


Posted in Java/Android onJuly 07, 2021
目录
  • 运行线程
    • 回调
    • 同步方法
    • 同步块
    • 死锁
    • 优先级
    • 暂停
      • 可以对IO阻塞
      • 可以对同步对象阻塞
      • 可以放弃
      • 可以休眠
      • 可以连接另一个线程
      • 可以等待一个对象
      • 可以结束
    • 可以被更高优先级线程抢占
  • 总结

 

运行线程

创建Thread的子类

public class ThreadChild extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("run");
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        ThreadChild t = new ThreadChild();
        t.start();
    }
}

创建Thread传入Runnable接口实现类

public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("run");
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new RunnableImpl());
        t.start();
    }
}

 

回调

ExecutorService线程池的Submit()可接收Runnable或者Callable.Callable执行结束后有返回值,Runnable执行结束后没有返回值.可以通过submit的返回对象Future的get方法获取返回返回值,需要注意的是get方法是一个阻塞方法.若线程没有执行完毕,则会阻塞get()直到线程执行结束后返回数据.

public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future<Integer> future = executorService.submit(() -> {
            TimeUnit.SECONDS.sleep( 3);
            return 1;
        });
        Future<?> future2 = executorService.submit(() -> {
        });
        Future<String> future3 = executorService.submit(() -> {
        }, "aaa");
        System.out.println(future.get());
        System.out.println(future2.get());
        System.out.println(future3.get());
    }

 

同步方法

synchronized关键字和方法组合使用后,该方法是一个同步方法。同步方法都有一个隐试的锁,多个线程同时执行该方法时,只能顺序执行,未强到锁的线程处于阻塞状态。另外静态方法和非静态方法使用的是不同的锁,非静态方法的锁是对象锁,若两个线程通过两个该类的对象调用那么互不影响。静态方法是类锁,即本类的Class对象。同步方法无法指定锁资源,要么是this锁,要么是Class锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        Thread t1 = new Thread(()->{
            test.synFunction();
        });
        Thread t2 = new Thread(()->{
            test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public synchronized void synFunction(){
        try {
            System.out.println("-------------");
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e) {}        
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(()->{
            Test.synFunction();
        });
        Thread t2 = new Thread(()->{
            Test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public static synchronized void synFunction(){
        try {
            System.out.println("-------------");
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e) {}        
    }
}

 

同步块

同步代码块可以指定锁对象,非静态方法可以指定任意的对象锁,或者任意的类锁。但静态方法只能使用任意的类锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Test lock = new Test();
        Thread t1 = new Thread(() -> {
            lock.synFunction();
        });
        Thread t2 = new Thread(() -> {
            lock.synFunction();
        });
        t1.start();
        t2.start();
    }
    public void synFunction() {
        synchronized (this) {//对象锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Test lock1 = new Test();
        Test lock2 = new Test();
        Thread t1 = new Thread(() -> {
            lock1.synFunction(lock1);
        });
        Thread t2 = new Thread(() -> {
            lock2.synFunction(lock2);
        });
        t1.start();
        t2.start();
    }
    public void synFunction(Object lock) {
        synchronized (lock) {//对象锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Test lock1 = new Test();
        Test lock2 = new Test();
        Thread t1 = new Thread(() -> {
            lock1.synFunction();
        });
        Thread t2 = new Thread(() -> {
            lock2.synFunction();
        });
        t1.start();
        t2.start();
    }
    public void synFunction() {
        synchronized (Test.class) {//类锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction();
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public static void synFunction() {
        synchronized (Object.class) {//类锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}

 

死锁

当多个线程竞争锁时,可能会导致死锁。一个线程由于没有得到一个锁而阻塞它也不会释放已经获取的锁。方法1获取锁的顺序是Test.class,Object.class。方法2获取锁的顺序是Object.class,Test.class。程序会陷入死锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction1();
        });
        Thread t2 = new Thread(() -> {
             Test.synFunction2();
        });
        t1.start();
        t2.start();
    }
    public static void synFunction1() {
        synchronized (Test.class) {// 类锁
            try {
                System.out.println("synFunction1-------------AAAAAAAAAAAAA");
                synchronized (Object.class) {// 类锁
                    try {
                        System.out.println("synFunction1-------------bbbbbbbbbbbbb");
                    } catch (Exception e) {
                    }
                }
            } catch (Exception e) {
            }
        }    
    }
    public static void synFunction2() {
        synchronized (Object.class) {// 类锁
            try {
                System.out.println("synFunction2-------------AAAAAAAAAAAAA");
            } catch (Exception e) {
            }
            synchronized (Test.class) {// 类锁
                try {
                    System.out.println("synFunction2-------------bbbbbbbbbbbbb");
                } catch (Exception e) {
                }
            }
        }
    }
}

 

优先级

不是所有线程创建时都是均等的,每个线程都有一个优先级,指定从0-10的整数。当多个线程运行时,虚拟机通常只运行最高优先级的线程,但这并不是一个严格的规则。在Java中10是最高优先级,0是最低优先级。默认优先级为5.并不是所有操作系统都支持这11个优先级。例如Windows只有7个优先级。优先级(1,2)(3,4)(6,7)(8,9)会做同样的处理。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
             Test.synFunction("bbbbbbbbbb");
        });
        t2.setPriority(9);
        t1.setPriority(1);
        t1.start();
        t2.start();
    }
    public static void synFunction(String name) {
        System.out.println(name+"--------------");
    }
}

 

暂停

为了能让其他线程有机会运行,一个线程有8中方式可以暂停或者指示它准备暂停。

 

可以对IO阻塞

要让网络程序中的线程自动放弃CPU控制权,最常见的方式是IO阻塞。由于CPU比网络和磁盘快的多,网络程序经常会在等待数据从网络到达或向网络发送数据时阻塞。即使只阻塞几毫秒,这一点时间也足够其他线程用来完成重要的任务。

 

可以对同步对象阻塞

线程在进入一个同步方法或代码块时也会阻塞。如果这个线程没有所同步对象的锁,而其他线程拥有这个锁,这个线程就会暂停,直到锁被释放为止。如果这个锁永远不会释放,那么这个线程会永久停止。

 

可以放弃

调用Thread.yield()静态方法可以做到显试的放弃线程控制权,这将通知虚拟机,可以优先执行其他线程。放弃并不会释放这个线程拥有的锁,因此在理想情况下被放弃的线程不要做任何的同步。如果等待运行的其他线程都是因为这个线程所拥有的同步资源而阻塞,那么这些线程将不能运行。实际上,控制权将回到唯一可以运行的线程,即刚刚放弃的这个线程,这很大程度上失去了放弃的意义。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public static void synFunction(String name) {
        for (int i = 0;; i++) {
            Thread.yield();
            System.out.println(name + "--------------" + i);
        }
    }
    public static void synFunction2(String name) {
        for (int i = 0;; i++)
            System.out.println(name + "--------------"+i);
    }
}

 

可以休眠

休眠是更有利的放弃方式。放弃只是表示线程愿意暂停,让其他有相同优先级的线程有机会运行,而进入休眠的线程有所不同,不管有没有其他线程准备运行,休眠线程都会暂停。这样一来,不只是其他有相同优先级的线程会得到机会,还会给较低优先级的线程运行机会。不过进入休眠的线程仍然拥有它已经获得得所有锁。因此其他需要相同锁得线程依然会阻塞,要避免在同步方法或块内让线程休眠。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public synchronized static void synFunction(String name) {
        try {
            System.out.println(name);
            Thread.sleep(1000 * 10);
        } catch (Exception e) {
        }
    }
    public synchronized static void synFunction2(String name) {
        System.out.println(name);
    }
}
package com.datang.bingxiang.demo;
import java.util.concurrent.TimeUnit;
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public synchronized static void synFunction(String name) {
        try {
            System.out.println(name);
            Thread.sleep(1000 * 3, 999999);//3000毫秒+999999毫秒(第二个参数不能超过999999,也就是不能超过1毫秒)
        } catch (Exception e) {
            System.out.println(e);
        }
    }
    public synchronized static void synFunction2(String name) {
        System.out.println(name);
    }
}

 

可以连接另一个线程

连接线程(既调用join()方法得线程A)等待被连接的线程(join()方法所属的线程对象B)执行完毕后才会执行。在A线程调用B线程的join()A线程会等待B线程执行结束后才会继续执行。要注意的是A线程并不会释放已经获取的锁资源。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa",t2);
        });
        
        t1.start();
        t2.start();
    }
    public  static void synFunction(String name,Thread t) {
        try {
            t.join();
            //t.join(1000);
            //t.join(1000,999999);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(name);
        }
    }
    public  static void synFunction2(String name) {
        try {
            Thread.sleep(1000*3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(name);
        }
    }
}

 

可以等待一个对象

线程可以等待一个它锁定的对象.在等待时,它会释放这个对象的锁并暂停,直到它得到其他线程的通知.另一个线程以某种方式修改这个对象,通知等待对象的线程,然后继续执行.等待会暂停执行,直到一个对象或资源到达某种状态.实际上,要等待某个特定的对象,希望暂停的线程首先必须使用synchronized获得这个对象的锁,然后调用这个对象的三个重载wait()方法之一.

public class Demo {
    public static void main(String[] args) throws Exception {
        Demo d = new Demo();
        Thread t1 = new Thread(() -> {
            d.a();
        });
        Thread t2 = new Thread(() -> {
            d.b();
        });
        t1.start();
        t2.start();
    }
    boolean flag = true;
    public synchronized void a() {
        try {
            while (true) {
                if (flag) {
                    System.out.println("执行AAAAAAAAAAA");
                    flag = false;
                } else {
                    wait();//等待,不限制等待时间
                    //wait(1000);//等待指定的时间,没有被notify唤醒也可以自己退出等待
                    //wait(1000,999999);//毫秒+纳秒的等待时间
                }
                notify();
            }
        } catch (Exception e) {
        }
    }
    public synchronized void b() {
        try {
            while (true) {
                if (!flag) {
                    System.out.println("执行BBBBBBBBBBB");
                    flag = true;
                } else {
                    wait();
                }
                notify();
            }
        } catch (Exception e) {
        }
    }
}

 

可以结束

线程要以合理的方式放弃CPU控制权,一种方式是结束.当run()方法返回线程时,线程将撤销,其他线程可以接管CPU.在网络应用程序中,包装一个阻塞操作的线程往往会这么做,例如线程从服务器下载一个文件,这样应用程序的其他部分就不会被阻塞.另一方面,如果run()方法太简单,总是很快结束,而不会紫色,那就存在一个很实际的问题:到底有没有必要生成一个线程.虚拟机在建立和撤销线程时会有很大的开销.如果线程会在极端的时间内结束,那么使用一次简单的方法调用而不是单独的线程可能会结束的更快.

 

可以被更高优先级线程抢占

Thread的setPriority(int priority)设置线程的优先级.

 

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注三水点靠木的更多内容!

Java/Android 相关文章推荐
MybatisPlus代码生成器的使用方法详解
Jun 13 Java/Android
Java 中的 Unsafe 魔法类的作用大全
Jun 26 Java/Android
分析JVM源码之Thread.interrupt系统级别线程打断
Jun 29 Java/Android
java设计模式--七大原则详解
Jul 21 Java/Android
浅谈sql_@SelectProvider及使用注意说明
Aug 04 Java/Android
SpringBoot中HttpSessionListener的简单使用方式
Mar 17 Java/Android
Java GUI编程菜单组件实例详解
Apr 07 Java/Android
教你在 Java 中实现 Dijkstra 最短路算法的方法
Apr 08 Java/Android
Spring Cloud Netflix 套件中的负载均衡组件 Ribbon
Apr 13 Java/Android
Android开发实现极为简单的QQ登录页面
Apr 24 Java/Android
HttpClient实现表单提交上传文件
Aug 14 Java/Android
Java获取字符串编码格式实现思路
Sep 23 Java/Android
Java 语言中Object 类和System 类详解
Jul 07 #Java/Android
新手初学Java List 接口
Jul 07 #Java/Android
Spring Boot 整合 Apache Dubbo的示例代码
Jul 04 #Java/Android
Java实现聊天机器人完善版
JavaGUI模仿QQ聊天功能完整版
JavaWeb Servlet实现网页登录功能
swagger如何返回map字段注释
You might like
批量修改RAR文件注释的php代码
2010/11/20 PHP
深入php常用函数的使用汇总
2013/06/08 PHP
PHP实现基于mysqli的Model基类完整实例
2016/04/08 PHP
js form action动态修改方法
2008/11/04 Javascript
自用js开发框架小成 学习js的朋友可以看看
2010/11/16 Javascript
用jquery生成二级菜单的实例代码
2013/06/24 Javascript
JavaScript运行时库属性一览表
2014/03/14 Javascript
Javascript获取随机数的实现方法
2016/06/22 Javascript
javascript中Number的方法小结
2016/11/21 Javascript
纯JS焦点图特效实例(可一个页面多用)
2016/12/07 Javascript
JS使用正则实现去掉字符串左右空格的方法
2016/12/27 Javascript
微信小程序 实现列表项滑动显示删除按钮的功能
2017/04/13 Javascript
JavaScript实现短信倒计时60s
2017/10/09 Javascript
jquery+css3实现熊猫tv导航代码分享
2018/02/12 jQuery
vue实现多个元素或多个组件之间动画效果
2018/09/25 Javascript
详解关于Vue单元测试的几个坑
2020/04/26 Javascript
手把手教你实现 Promise的使用方法
2020/09/02 Javascript
jQuery实现增删改查
2020/12/22 jQuery
[02:15]2015国际邀请赛选手档案IG.Ferrari 430
2015/07/30 DOTA
python生成指定尺寸缩略图的示例
2014/05/07 Python
Python实现二分法算法实例
2015/02/02 Python
Win7下Python与Tensorflow-CPU版开发环境的安装与配置过程
2018/01/04 Python
对python中for、if、while的区别与比较方法
2018/06/25 Python
python hook监听事件详解
2018/10/25 Python
Python3之字节串bytes与字节数组bytearray的使用详解
2019/08/27 Python
python实现生成Word、docx文件的方法分析
2019/08/30 Python
Python 一行代码能实现丧心病狂的功能
2020/01/18 Python
Tensorflow 多线程设置方式
2020/02/06 Python
python 输入字符串生成所有有效的IP地址(LeetCode 93号题)
2020/10/15 Python
Django多个app urls配置代码实例
2020/11/26 Python
手摸手教你用canvas实现给图片添加平铺水印的实现
2019/08/20 HTML / CSS
VisionPros美国站:加拿大在线隐形眼镜和眼镜零售商
2020/02/11 全球购物
Farfetch中文官网:奢侈品牌时尚购物平台
2020/03/15 全球购物
你在项目中用到了xml技术的哪些方面?如何实现的?
2014/01/26 面试题
《美丽的小兴安岭》教学反思
2014/02/26 职场文书
计算机应用应届生求职信
2014/07/12 职场文书