黑马程序员_多线程和String类

 
 
------------- android培训、java培训、java博客、java学习型技术博客、期待与您交流! -------------

多线程

进程与线程 进程是程序的一次动态执行过程,它经历了代码加载、执行到执行完毕整个过程, 运行一个程序,就会启动一个进程,这时操作系统会为进程分配资源,最主要资源即内存空间; 多进程操作系统指能同时运行多个进程(程序),每个进程随机获得CPU执行时间片。 线程是比进程更小的执行单位,它是进程内部单一的顺序控制流; 多线程是指一个进程中有多个线程同时运行,形成多条执行线索; 它是实现并发机制的一种有效手段,目的是为了最大限度利用CPU资源。 区别 1、同为基本执行单元,线程是划分比进程更小的执行单位; 2、每个进程都有一段专用的内存空间,但线程却共享内存单元(包括代码和数据), 当有新线程产生,操作系统不分配新内存空间,而是让新线程共享原有进程的内存, 因此线程间通信很容易,速度也很快。 创建与启动 线程的创建都是靠实现Runnable接口、复写run方法而来的, 线程的启动却都是通过Thread类对象调用start方法,有以下两种方式: 1、java中Thread类实现了Runnable接口,所以可直接定义类继承Thread, 然后再将run方法复写,最后直接调用父类已有的start方法启动线程即可; 2、定义类实现Runnable接口、复写run方法,将该类对象以多态形式传递给 Thread对象,再通过Thread对象调用start方法。 两者比较 实现方式避免了java语言中单继承的局限性,方便应用; 继承方式是将运行代码存储于子类run方法中,而另者是存储于Runnabl接口run方法中, 继承方式一个对象只能调用一次start方法,因而如果想要多个线程运行它,则只能创建多个对象, 如果创建了多个对象的话,则只能使其数据为共享数据。 注意: run方法只是用于存储线程要运行的代码; start方法才能启动一个线程。 Thread类 构造函数 Thread(Runnable target),多态,new新的Thread对象 Thread(String name),new一个有名字的Thread对象 方法 String getName()   返回该线程名称 static Thread currentThread()  返回当前执行线程对象的引用(选择性用this代替) static void sleep(long millis)  让当前执行线程暂休眠,另有异常抛出 start()   使线程开执行,JVM开始调用该线程run方法 interrupt()  将处于冻结状态的线程强制的恢复到运行状态,可与catch结合用作停止线程 setDaemon  守护线程/用户线程/后台线程(线程.setDaemon(true))必须在线程启动前调用 当所有的前台线程结束后,后台线程会自动结束,其它运行方式都一样 toString()  输出线程名+线程级别+线程组 setPriority  设置优先级,1-10级别,一般不写数字,用MAX(MIN NORM)_PRIORITY固定常量代表 e.g:线程.setPriority(Thread.MAX_PRIORITY) static yield()  暂停当前正在执行的线程对象,并执行其它线程 join() 当其它线程执行了此线程的.join()方法时,其它线程就会等待此线程执行完在执行 线程状态 1、执行状态 2、结束/消亡状态 3、冻结状态,sleep(long millis)、wait()让线程处于睡眠或等待即冻结状态 4、阻塞/临时状态, 有执行资格但没有cpu执行权 wait和sleep区别:  wait:可以指定时间也可以不指定时间。不指定时间,只能由对应的notify或者notifyAll来唤醒。 sleep:必须指定时间,时间到自动从冻结状态转成运行状态(临时阻塞状态) wait:线程会释放执行权,而且线程会释放锁,即其它线程可进入同步中执行; Sleep:线程会释放执行权,但不是不释放锁,即其它线程不可进入同步中执行 另:wait()、notify()、notifyAll()在操作同步中线程时,都必须要标识他们所操作线程的锁,   同一个锁上的被等待线程,只可以被同一个锁上notify唤醒,即等待和唤醒必须是同一把锁   而锁是任意对象,所以可以被任意对象调用的方法需定义在Obeject类中 线程安全 多线程运行代码语句有操作共享数据,当一个线程操作了共享数据但没有执行完相应的后续操作, 这时另一个线程获得CPU执行权继续操作共享数据再执行后续操作,就有可能导致错误。 要解决这种隐患,则需要明确多线程执行代码中哪些语句操作了共享数据, 然后保证同一时间只有一个线程执行这些操作共享数据的语句。 线程同步 同步代码块 synchronized(对象){ 需同步语句 }   线程执行到该语句,都先进行判断,语句中没有线程则继续执行否则等待; 另接受的对象可以自定义为任何对象,对象也就是锁; 同步函数 synchronized修饰的函数即同步函数 函数需要被对象调用,都有一个所属对象引用,就是this,同步函数的锁也就是this 同步前提 1、必须要有两个或者两个以上线程 2、必须是多个线程使用同一个锁 同步死锁  通常将同步进行嵌套,就有可能出现。同步函数中有同步代码块,同步代码块中还有同步函数。 两个窗口同时卖票,验证非静态同步函数所是this 同理可将ticket变量用静态修饰,同步函数变为静态的来验证静态函数的锁是类名.class对象 class Ticket implements Runnable{ private int ticket = 100; boolean flag = true; public void run(){ if(flag){ while(true){ //同步代码块 synchronized(this){  //验证非静态同步函数是不是this,看所得票是否有误 if (ticket>0){ try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"."+ticket--); } } } } else while(true) method(); } //同步函数 public synchronized void method(){ if (ticket>0){ try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+":"+ticket--); } } } class Demo1{ public static void main(String[] args){ Ticket t = new Ticket(); new Thread(t).start(); try{Thread.sleep(10);}catch(Exception e){} //保证第一个线程进入到第一个循环里 t.flag = false;  //让第二个线程进入第二个循环里 new Thread(t).start(); } } 单例设计模式 1、饿汉式 class Single1 { private static final Single1 s1 = new Single1(); private Single1(){} public static Single1 getSingle1(){ return s1; } } 2、懒汉式 class Single2 { private static Single2 s2 = null; private Single2(){} public static Single2 getSingle2(){ if (s2==null){ synchronized(this){ if (s2==null) return s2 = new Single2(); } } return s2; } } 线程间通信 当多个线程在操作同一个资源,但是操作的动作却不一样时,就需要明确各个线程 执行的先后顺序,这样线程间就有了通信。 步骤 1、将资源封装成对象。 2、将线程执行的任务(任务其实就是run方法。)也封装成对象。 3、通过等待+换新配合逻辑条件来操控各个线程的执行 JDK1.5版本 java.util.concurrent.locks.*; 1、同步语句或函数用Lock锁接口替代; 2、wait()、notify()、notifyAll被Condition接口中   await()、signal()、signalAll()替代 注意这些方法需与各自锁搭档执行,所以都要定义在同步或锁中。 见如下事例,多个线程生产和消费商品,生产1个消费1个; import java.util.concurrent.locks.*; class Resource{ private String product; private int count =1; //锁旗标,实现不同操作线程依次交替执行 private boolean flag=false; private Lock lock = new ReentrantLock(); //一个锁上可有多个condition对象,从而可指定唤醒或等待某个线程 private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); public void set(String product){ lock.lock(); try{ //注意while与if的区别,while中线程唤醒会继续判断条件,if中却直接向下执行语句 while (flag) condition_pro.await(); this.product = product+count++; System.out.println(Thread.currentThread().getName()+"生产:"+this.product); flag = true; condition_con.signal(); } catch(InterruptedException e){} finally{  //finally操作事例 lock.unlock();//一定要有关闭或释放锁动作 } } public void get() { lock.lock(); try{ while (!flag) condition_con.await(); System.out.println(Thread.currentThread().getName()+"消费:  "+product); flag = false; condition_pro.signal();//指定唤醒线程 } catch(InterruptedException e){} finally{ lock.unlock(); } } } class Producer implements Runnable{ private Resource res; Producer(Resource res) { this.res = res; } public void run(){ while (true) res.set("商品-"); } } class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res = res; } public void run(){ while (true) res.get(); } } class Demo2{ public static void main(String[] args){ Resource res = new Resource(); Producer pro = new Producer(res); Consumer con = new Consumer(res); new Thread(pro).start(); new Thread(pro).start(); new Thread(con).start(); new Thread(con).start(); } } 停止线程 停止线程就是让线程运行的代码结束,即结束run方法;stop方法可以停止线程,但是已经过时; 通常run方法里肯定定义循环。所以只要结束循环即可。 1、定义循环标记(flag),通过改变循环标记,来控制线程循环; 2、如果线程处于了冻结状态,是不可能读到标记的,这时就需要通过Thread类中的interrupt方法,   将其冻结状态强制清除。让线程恢复具备执行资格的状态,线程则可以读到标记,然后结束。 线程简写 1、 new Thread(){ public void run(){ 执行代码 } }.start(); 2、 Runnable r = new Runnable(){ public void run(){ 执行代码 } }; new Thread(r).start();

String类

特点:一旦被初始化,就不能被改变。它既是一个对象,又是一个字符串常量。 构造函数 1、字节数组转字符串,可指定编码表解码 String(byte[] bytes) String(byte[] bytes,int offset,int length,Charset charset) 2、字符数组转字符串 String(char[] value,int offset,int count) 3、字符串缓冲区转字符串 String(StringBuilder builder) 方法 1、获取 1.1 字符串中包含的字符数,也就是字符串的长度 int length(); (数组arr.length是属性没有括号) 1.2 按指定角标获取字符 char charAt(int index); 1.3 按字符获取该字符在字符串中首次出现索引,若无返回-1 int indexOf(int ch);  注意字符会自动按编码表转化成int型 int indexOf(int ch,fromIndex);   指定起始位 int indexOf(String str)   查字符串 int indexOf(Strign str,fromIndex):  2、判断 2.1 字符串中是否包含某一个字串 boolean contains(CharSequence s) int indexOf(str)也可以用于对指定字符串判断是否包含 e.g: if(str.indexOf("aa")!=-1) 2.2 字符串中是否有内容 boolean isEmpty();相当于判断length是否为0; 2.3 字符串是否以自定内容开头 boolean startsWith(str) 2.4 字符串是否以自定内容结尾 boolean endsWith(str);//刷选文件的时候是有用 2.5 判断字符串的内容是否相同,复写了Object类中的equals方法 boolean equals(str);//不忽略大小写 2.6 判断内容是否相同,并忽略大小写。应用,密码大小写忽略。 boolean equalsIgnoreCase(); 3、转换 3.1 将字符串转成字符数组 char[] toCharArray(); 3.2 将字符串转成字节数组 byte[] getBytes(); //可以按照指定编码表转化 3.3 将字符数组转成字符串,静态方法 static String copyValueOf(char[]) static String copyValueOf(char[] data;int offset,int count) static String valueOf(char[]); 3.4 将基本数据类型转成字符串 static String valueOf(基本数据类型 变量名) string.valueOf(3);相当于3+"";前者较专业     4、替换 String replace(oldchar,newchar)  //记住先old后是new String replace(oldstr,newstr)  //替换字符串 5、切割 String[] split(regex)  //切割后为字符串数组 6、获取子串 String substring(int beginIndex); String substring(int begin,int end);//算头不算尾 注意:end的最大值为str.length(),因为它不包括尾 7、其它 7.1 将字符串转成大写或者小写 String  toUpperCase(); String  toLowwerCase(); 7.2 将字符串两端的多个空格去除 String trim(); 7.3 自然顺序的比较,复写了compareable比较方法 int compareTo(String);从字符串第一字母开始比较,返回int数值 StringBuffer 字符串缓冲区,是一个容器,可以用于对数据进行修改, 特点 1、长度是可以变化的,数组也是容器但是长度是固定的, 2、可以直接操作多个数据类型,数组一次只能操作一种类型 3、最终会通过toString方法变成字符串,或String(StringBuffer sb) 方法 1、存储 StringBuffer append(data)  将制定数据作为参数添加到已有数据结尾处 StringBuffer insert(index,数据) 可以将数据插入到制定index位置 2、删除 StringBuffer delete(int start,int end):删除缓冲区中的数据,包含头不包含尾 StringBuffer deletCharAt(index): 删除指定位置字符 3、获取 char charAt(int index)   获取指定角标字符 int  indexOf(String str) int  lastIndexOf(String str) int  length() String substring(int start,int end)  返回String类型 4、修改 StringBuffer  replace(start,end,String str); void   setCharAt(index,char ch); //没有返回值 5、反转 StringBuffer reverse(); 6、 将缓冲区中指定数据复制到指定字符数组中, void getChars(int srcBegin,int srcEnd,char[] des,int detBegin) 字符串起始结束位置,目标数组,目标数组开始位置 因为对数组的操作是有记忆的,所以返回类型为void StringBuilder  JDK1.5版本后 区别 StringBuffer 是线程同步 StringBuilder 是线程不同步 以后建议使用后者,因为前者每次访问需要判断锁,效率相对较低,碰到多线程自定义锁。

基本数据类型包装类

格式  基本数据类型   引用数据类型 byte              Byte short             Short int               Integer long              Long boolean           Boolean char              Character 类型转换 最常见操作就是基本数据类型和字符串类型之间的转换 1、字符串类型转基本数据类型   基本数据类型 变量名 = new 引用数据类型.parse基本数据类型(String str);    e.g: int num = new Integer.parseInt("123");   或者通过 static intVlaue() 方法转换    new Integer("123").intValue(); 2、基本数据类型转字符串类型 字符串类型 变量名 = 基本数据值+"" ; 或, 引用数据类型.toString(int num); e.g:  Stirng str = Integer.toString(12); 进制转换 十进制转其它进制字符串表达形式   static String toBinaryString(int i)   static String toOctaryString(int i)   static String toHexString(int i) 其它进制字符串转成十进制   static int parseInt(String ste,int radix);radix代表进制 新特性 1、自动封装和自动拆箱    Integer x1 = 1 ; //自动封装成对象 Integer x2 = x1 + 2 ; //先对象.intValue变成int数据进行运算后封装成对象 注意x1可接收null,所以写代码时要注意判断,否则会出现空指针异常 2、开辟空间 Integer m1 = 128; Integer m2 =128; //m1 != m2 Integer n1 = 127; Integer n2 =127; //n1 != n2 方法 1、equals, 比较两个对象数值是否相等 2、compareTo,比较大小,后续集合中复写比较方法时候常用到

------------- android培训java培训、java博客、java学习型技术博客、期待与您交流! -------------
详情请查看:http://edu.csdn.net/heima/
黑马程序员多线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值